mirror of
https://github.com/home-assistant/core.git
synced 2026-02-15 07:36:16 +00:00
Make template weather consistent with itself and other platforms (#159607)
This commit is contained in:
@@ -239,7 +239,13 @@ CONFIG_SECTION_SCHEMA = vol.All(
|
||||
cv.ensure_list, [vacuum_platform.VACUUM_YAML_SCHEMA]
|
||||
),
|
||||
vol.Optional(DOMAIN_WEATHER): vol.All(
|
||||
cv.ensure_list, [weather_platform.WEATHER_YAML_SCHEMA]
|
||||
cv.ensure_list,
|
||||
[
|
||||
vol.Any(
|
||||
weather_platform.WEATHER_YAML_SCHEMA,
|
||||
weather_platform.WEATHER_MODERN_YAML_SCHEMA,
|
||||
)
|
||||
],
|
||||
),
|
||||
},
|
||||
),
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
from collections.abc import Callable
|
||||
from dataclasses import asdict, dataclass
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, Literal, Self
|
||||
|
||||
import voluptuous as vol
|
||||
@@ -71,6 +72,8 @@ from .schemas import (
|
||||
from .template_entity import TemplateEntity
|
||||
from .trigger_entity import TriggerEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CHECK_FORECAST_KEYS = (
|
||||
set()
|
||||
.union(Forecast.__annotations__.keys())
|
||||
@@ -159,8 +162,9 @@ LEGACY_FIELDS = {
|
||||
CONF_WIND_SPEED_TEMPLATE: CONF_WIND_SPEED,
|
||||
}
|
||||
|
||||
|
||||
WEATHER_COMMON_SCHEMA = vol.Schema(
|
||||
# These options that are templates all have _template. These fields will
|
||||
# enter deprecation after legacy templates are removed.
|
||||
WEATHER_COMMON_LEGACY_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_APPARENT_TEMPERATURE_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_ATTRIBUTION_TEMPLATE): cv.template,
|
||||
@@ -186,32 +190,7 @@ WEATHER_COMMON_SCHEMA = vol.Schema(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
WEATHER_YAML_SCHEMA = (
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_UV_INDEX_TEMPLATE): cv.template,
|
||||
}
|
||||
)
|
||||
.extend(WEATHER_COMMON_SCHEMA.schema)
|
||||
.extend(
|
||||
make_template_entity_common_modern_schema(WEATHER_DOMAIN, DEFAULT_NAME).schema
|
||||
)
|
||||
)
|
||||
|
||||
PLATFORM_SCHEMA = (
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
}
|
||||
)
|
||||
.extend(WEATHER_COMMON_SCHEMA.schema)
|
||||
.extend(WEATHER_PLATFORM_SCHEMA.schema)
|
||||
)
|
||||
|
||||
|
||||
WEATHER_CONFIG_ENTRY_SCHEMA = vol.Schema(
|
||||
WEATHER_COMMON_MODERN_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_APPARENT_TEMPERATURE): cv.template,
|
||||
vol.Optional(CONF_ATTRIBUTION): cv.template,
|
||||
@@ -236,7 +215,40 @@ WEATHER_CONFIG_ENTRY_SCHEMA = vol.Schema(
|
||||
vol.Optional(CONF_WIND_SPEED): cv.template,
|
||||
vol.Optional(CONF_WIND_SPEED_UNIT): vol.In(SpeedConverter.VALID_UNITS),
|
||||
}
|
||||
).extend(TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA.schema)
|
||||
)
|
||||
|
||||
|
||||
WEATHER_YAML_SCHEMA = (
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_UV_INDEX_TEMPLATE): cv.template,
|
||||
}
|
||||
)
|
||||
.extend(WEATHER_COMMON_LEGACY_SCHEMA.schema)
|
||||
.extend(
|
||||
make_template_entity_common_modern_schema(WEATHER_DOMAIN, DEFAULT_NAME).schema
|
||||
)
|
||||
)
|
||||
|
||||
WEATHER_MODERN_YAML_SCHEMA = WEATHER_COMMON_MODERN_SCHEMA.extend(
|
||||
make_template_entity_common_modern_schema(WEATHER_DOMAIN, DEFAULT_NAME).schema
|
||||
)
|
||||
|
||||
PLATFORM_SCHEMA = (
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.template,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
}
|
||||
)
|
||||
.extend(WEATHER_COMMON_LEGACY_SCHEMA.schema)
|
||||
.extend(WEATHER_PLATFORM_SCHEMA.schema)
|
||||
)
|
||||
|
||||
|
||||
WEATHER_CONFIG_ENTRY_SCHEMA = WEATHER_COMMON_MODERN_SCHEMA.extend(
|
||||
TEMPLATE_ENTITY_COMMON_CONFIG_ENTRY_SCHEMA.schema
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
@@ -699,6 +711,7 @@ class TriggerWeatherEntity(TriggerEntity, AbstractTemplateWeather, RestoreEntity
|
||||
|
||||
for key in (
|
||||
CONF_APPARENT_TEMPERATURE,
|
||||
CONF_ATTRIBUTION,
|
||||
CONF_CLOUD_COVERAGE,
|
||||
CONF_DEW_POINT,
|
||||
CONF_FORECAST_DAILY,
|
||||
@@ -752,6 +765,7 @@ class TriggerWeatherEntity(TriggerEntity, AbstractTemplateWeather, RestoreEntity
|
||||
write_ha_state = False
|
||||
for key, updater in (
|
||||
(CONF_APPARENT_TEMPERATURE, self._update_apparent_temperature),
|
||||
(CONF_ATTRIBUTION, self._update_attribution),
|
||||
(CONF_CLOUD_COVERAGE, self._update_coverage),
|
||||
(CONF_CONDITION, self._update_condition),
|
||||
(CONF_DEW_POINT, self._update_dew_point),
|
||||
@@ -772,28 +786,39 @@ class TriggerWeatherEntity(TriggerEntity, AbstractTemplateWeather, RestoreEntity
|
||||
if write_ha_state:
|
||||
self.async_write_ha_state()
|
||||
|
||||
def _check_forecast(
|
||||
self,
|
||||
forecast_type: Literal["daily", "hourly", "twice_daily"],
|
||||
key: str,
|
||||
) -> list[Forecast]:
|
||||
result = self._rendered.get(key)
|
||||
try:
|
||||
return self._validate_forecast(forecast_type, result) or []
|
||||
except vol.Invalid as err:
|
||||
_LOGGER.error(
|
||||
(
|
||||
"Error validating template result '%s' "
|
||||
"for attribute '%s' in entity %s "
|
||||
"validation message '%s'"
|
||||
),
|
||||
result,
|
||||
key,
|
||||
self.entity_id,
|
||||
err.msg,
|
||||
)
|
||||
return []
|
||||
|
||||
async def async_forecast_daily(self) -> list[Forecast]:
|
||||
"""Return the daily forecast in native units."""
|
||||
return (
|
||||
self._validate_forecast("daily", self._rendered.get(CONF_FORECAST_DAILY))
|
||||
or []
|
||||
)
|
||||
return self._check_forecast("daily", CONF_FORECAST_DAILY)
|
||||
|
||||
async def async_forecast_hourly(self) -> list[Forecast]:
|
||||
"""Return the daily forecast in native units."""
|
||||
return (
|
||||
self._validate_forecast("hourly", self._rendered.get(CONF_FORECAST_HOURLY))
|
||||
or []
|
||||
)
|
||||
return self._check_forecast("hourly", CONF_FORECAST_HOURLY)
|
||||
|
||||
async def async_forecast_twice_daily(self) -> list[Forecast]:
|
||||
"""Return the daily forecast in native units."""
|
||||
return (
|
||||
self._validate_forecast(
|
||||
"twice_daily", self._rendered.get(CONF_FORECAST_TWICE_DAILY)
|
||||
)
|
||||
or []
|
||||
)
|
||||
return self._check_forecast("twice_daily", CONF_FORECAST_TWICE_DAILY)
|
||||
|
||||
@property
|
||||
def extra_restore_state_data(self) -> WeatherExtraStoredData:
|
||||
|
||||
@@ -163,19 +163,20 @@ async def setup_entity(
|
||||
) -> None:
|
||||
"""Do setup of a template entity based on the configuration style."""
|
||||
if style == ConfigurationStyle.LEGACY:
|
||||
entity_config = {
|
||||
**({"value_template": state_template} if state_template else {}),
|
||||
**config,
|
||||
**(extra_config or {}),
|
||||
**({"attribute_templates": attributes} if attributes else {}),
|
||||
}
|
||||
# Lock and weather platforms do not use a slug.
|
||||
if platform_setup.legacy_slug is None:
|
||||
config = {"name": platform_setup.object_id, **entity_config}
|
||||
else:
|
||||
config = {platform_setup.object_id: entity_config}
|
||||
|
||||
await async_setup_legacy_platforms(
|
||||
hass,
|
||||
platform_setup.domain,
|
||||
platform_setup.legacy_slug,
|
||||
count,
|
||||
{
|
||||
platform_setup.object_id: {
|
||||
**({"value_template": state_template} if state_template else {}),
|
||||
**config,
|
||||
**(extra_config or {}),
|
||||
**({"attribute_templates": attributes} if attributes else {}),
|
||||
}
|
||||
},
|
||||
hass, platform_setup.domain, platform_setup.legacy_slug, count, config
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
# serializer version: 1
|
||||
# name: test_forecasts[config0-1-weather-get_forecasts]
|
||||
# name: test_forecasts[ConfigurationStyle.LEGACY-config0]
|
||||
dict({
|
||||
'weather.forecast': dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[config0-1-weather-get_forecasts].1
|
||||
# name: test_forecasts[ConfigurationStyle.LEGACY-config0].1
|
||||
dict({
|
||||
'weather.forecast': dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[config0-1-weather-get_forecasts].2
|
||||
# name: test_forecasts[ConfigurationStyle.LEGACY-config0].2
|
||||
dict({
|
||||
'weather.forecast': dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'fog',
|
||||
@@ -29,10 +39,227 @@
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[config0-1-weather-get_forecasts].3
|
||||
# name: test_forecasts[ConfigurationStyle.LEGACY-config0].3
|
||||
dict({
|
||||
'weather.forecast': dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 16.9,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config1]
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config1].1
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config1].2
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'fog',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'is_daytime': True,
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config1].3
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 16.9,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config3]
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config3].1
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config3].2
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'fog',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'is_daytime': True,
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.MODERN-config3].3
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 16.9,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config2]
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config2].1
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config2].2
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'fog',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'is_daytime': True,
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config2].3
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 16.9,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config4]
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config4].1
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config4].2
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'fog',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'is_daytime': True,
|
||||
'temperature': 14.2,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_forecasts[ConfigurationStyle.TRIGGER-config4].3
|
||||
dict({
|
||||
'weather.template_weather': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'cloudy',
|
||||
'datetime': '2023-02-17T14:00:00+00:00',
|
||||
'temperature': 16.9,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
@@ -76,49 +303,3 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_trigger_weather_services[config0-1-template-get_forecasts]
|
||||
dict({
|
||||
'weather.test': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'sunny',
|
||||
'datetime': '2023-10-19T06:50:05-07:00',
|
||||
'precipitation': 20.0,
|
||||
'temperature': 20.0,
|
||||
'templow': 15.0,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_trigger_weather_services[config0-1-template-get_forecasts].1
|
||||
dict({
|
||||
'weather.test': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'sunny',
|
||||
'datetime': '2023-10-19T06:50:05-07:00',
|
||||
'precipitation': 20.0,
|
||||
'temperature': 20.0,
|
||||
'templow': 15.0,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_trigger_weather_services[config0-1-template-get_forecasts].2
|
||||
dict({
|
||||
'weather.test': dict({
|
||||
'forecast': list([
|
||||
dict({
|
||||
'condition': 'sunny',
|
||||
'datetime': '2023-10-19T06:50:05-07:00',
|
||||
'is_daytime': True,
|
||||
'precipitation': 20.0,
|
||||
'temperature': 20.0,
|
||||
'templow': 15.0,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user