mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Implement Apparent temperature in Weather entity component (#95070)
This commit is contained in:
parent
38614bc3f0
commit
6ad3b60adf
@ -30,6 +30,7 @@ from homeassistant.helpers.typing import ConfigType
|
|||||||
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
|
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
ATTR_WEATHER_APPARENT_TEMPERATURE,
|
||||||
ATTR_WEATHER_HUMIDITY,
|
ATTR_WEATHER_HUMIDITY,
|
||||||
ATTR_WEATHER_OZONE,
|
ATTR_WEATHER_OZONE,
|
||||||
ATTR_WEATHER_PRECIPITATION_UNIT,
|
ATTR_WEATHER_PRECIPITATION_UNIT,
|
||||||
@ -73,6 +74,8 @@ ATTR_FORECAST_PRECIPITATION: Final = "precipitation"
|
|||||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: Final = "precipitation_probability"
|
ATTR_FORECAST_PRECIPITATION_PROBABILITY: Final = "precipitation_probability"
|
||||||
ATTR_FORECAST_NATIVE_PRESSURE: Final = "native_pressure"
|
ATTR_FORECAST_NATIVE_PRESSURE: Final = "native_pressure"
|
||||||
ATTR_FORECAST_PRESSURE: Final = "pressure"
|
ATTR_FORECAST_PRESSURE: Final = "pressure"
|
||||||
|
ATTR_FORECAST_NATIVE_APPARENT_TEMP: Final = "native_apparent_temperature"
|
||||||
|
ATTR_FORECAST_APPARENT_TEMP: Final = "apparent_temperature"
|
||||||
ATTR_FORECAST_NATIVE_TEMP: Final = "native_temperature"
|
ATTR_FORECAST_NATIVE_TEMP: Final = "native_temperature"
|
||||||
ATTR_FORECAST_TEMP: Final = "temperature"
|
ATTR_FORECAST_TEMP: Final = "temperature"
|
||||||
ATTR_FORECAST_NATIVE_TEMP_LOW: Final = "native_templow"
|
ATTR_FORECAST_NATIVE_TEMP_LOW: Final = "native_templow"
|
||||||
@ -199,6 +202,7 @@ class WeatherEntity(Entity):
|
|||||||
|
|
||||||
_attr_native_pressure: float | None = None
|
_attr_native_pressure: float | None = None
|
||||||
_attr_native_pressure_unit: str | None = None
|
_attr_native_pressure_unit: str | None = None
|
||||||
|
_attr_native_apparent_temperature: float | None = None
|
||||||
_attr_native_temperature: float | None = None
|
_attr_native_temperature: float | None = None
|
||||||
_attr_native_temperature_unit: str | None = None
|
_attr_native_temperature_unit: str | None = None
|
||||||
_attr_native_visibility: float | None = None
|
_attr_native_visibility: float | None = None
|
||||||
@ -272,6 +276,11 @@ class WeatherEntity(Entity):
|
|||||||
return
|
return
|
||||||
self.async_registry_entry_updated()
|
self.async_registry_entry_updated()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_apparent_temperature(self) -> float | None:
|
||||||
|
"""Return the apparent temperature in native units."""
|
||||||
|
return self._attr_native_temperature
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@property
|
@property
|
||||||
def temperature(self) -> float | None:
|
def temperature(self) -> float | None:
|
||||||
@ -600,6 +609,20 @@ class WeatherEntity(Entity):
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
data[ATTR_WEATHER_TEMPERATURE] = temperature
|
data[ATTR_WEATHER_TEMPERATURE] = temperature
|
||||||
|
|
||||||
|
if (apparent_temperature := self.native_apparent_temperature) is not None:
|
||||||
|
from_unit = self.native_temperature_unit or self._default_temperature_unit
|
||||||
|
to_unit = self._temperature_unit
|
||||||
|
try:
|
||||||
|
apparent_temperature_f = float(apparent_temperature)
|
||||||
|
value_apparent_temp = UNIT_CONVERSIONS[ATTR_WEATHER_TEMPERATURE_UNIT](
|
||||||
|
apparent_temperature_f, from_unit, to_unit
|
||||||
|
)
|
||||||
|
data[ATTR_WEATHER_APPARENT_TEMPERATURE] = round_temperature(
|
||||||
|
value_apparent_temp, precision
|
||||||
|
)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
data[ATTR_WEATHER_APPARENT_TEMPERATURE] = apparent_temperature
|
||||||
|
|
||||||
data[ATTR_WEATHER_TEMPERATURE_UNIT] = self._temperature_unit
|
data[ATTR_WEATHER_TEMPERATURE_UNIT] = self._temperature_unit
|
||||||
|
|
||||||
if (humidity := self.humidity) is not None:
|
if (humidity := self.humidity) is not None:
|
||||||
@ -686,6 +709,26 @@ class WeatherEntity(Entity):
|
|||||||
value_temp, precision
|
value_temp, precision
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
forecast_apparent_temp := forecast_entry.pop(
|
||||||
|
ATTR_FORECAST_NATIVE_APPARENT_TEMP,
|
||||||
|
forecast_entry.get(ATTR_FORECAST_NATIVE_APPARENT_TEMP),
|
||||||
|
)
|
||||||
|
) is not None:
|
||||||
|
with suppress(TypeError, ValueError):
|
||||||
|
forecast_apparent_temp = float(forecast_apparent_temp)
|
||||||
|
value_apparent_temp = UNIT_CONVERSIONS[
|
||||||
|
ATTR_WEATHER_TEMPERATURE_UNIT
|
||||||
|
](
|
||||||
|
forecast_apparent_temp,
|
||||||
|
from_temp_unit,
|
||||||
|
to_temp_unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
forecast_entry[ATTR_FORECAST_APPARENT_TEMP] = round_temperature(
|
||||||
|
value_apparent_temp, precision
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
forecast_temp_low := forecast_entry.pop(
|
forecast_temp_low := forecast_entry.pop(
|
||||||
ATTR_FORECAST_NATIVE_TEMP_LOW,
|
ATTR_FORECAST_NATIVE_TEMP_LOW,
|
||||||
|
@ -22,6 +22,7 @@ ATTR_WEATHER_HUMIDITY = "humidity"
|
|||||||
ATTR_WEATHER_OZONE = "ozone"
|
ATTR_WEATHER_OZONE = "ozone"
|
||||||
ATTR_WEATHER_PRESSURE = "pressure"
|
ATTR_WEATHER_PRESSURE = "pressure"
|
||||||
ATTR_WEATHER_PRESSURE_UNIT = "pressure_unit"
|
ATTR_WEATHER_PRESSURE_UNIT = "pressure_unit"
|
||||||
|
ATTR_WEATHER_APPARENT_TEMPERATURE = "apparent_temperature"
|
||||||
ATTR_WEATHER_TEMPERATURE = "temperature"
|
ATTR_WEATHER_TEMPERATURE = "temperature"
|
||||||
ATTR_WEATHER_TEMPERATURE_UNIT = "temperature_unit"
|
ATTR_WEATHER_TEMPERATURE_UNIT = "temperature_unit"
|
||||||
ATTR_WEATHER_VISIBILITY = "visibility"
|
ATTR_WEATHER_VISIBILITY = "visibility"
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
"pressure_unit": {
|
"pressure_unit": {
|
||||||
"name": "Pressure unit"
|
"name": "Pressure unit"
|
||||||
},
|
},
|
||||||
|
"apparent_temperature": {
|
||||||
|
"name": "Apparent temperature"
|
||||||
|
},
|
||||||
"temperature": {
|
"temperature": {
|
||||||
"name": "Temperature"
|
"name": "Temperature"
|
||||||
},
|
},
|
||||||
|
@ -6,12 +6,14 @@ import pytest
|
|||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
ATTR_CONDITION_SUNNY,
|
ATTR_CONDITION_SUNNY,
|
||||||
ATTR_FORECAST,
|
ATTR_FORECAST,
|
||||||
|
ATTR_FORECAST_APPARENT_TEMP,
|
||||||
ATTR_FORECAST_PRECIPITATION,
|
ATTR_FORECAST_PRECIPITATION,
|
||||||
ATTR_FORECAST_PRESSURE,
|
ATTR_FORECAST_PRESSURE,
|
||||||
ATTR_FORECAST_TEMP,
|
ATTR_FORECAST_TEMP,
|
||||||
ATTR_FORECAST_TEMP_LOW,
|
ATTR_FORECAST_TEMP_LOW,
|
||||||
ATTR_FORECAST_WIND_BEARING,
|
ATTR_FORECAST_WIND_BEARING,
|
||||||
ATTR_FORECAST_WIND_SPEED,
|
ATTR_FORECAST_WIND_SPEED,
|
||||||
|
ATTR_WEATHER_APPARENT_TEMPERATURE,
|
||||||
ATTR_WEATHER_OZONE,
|
ATTR_WEATHER_OZONE,
|
||||||
ATTR_WEATHER_PRECIPITATION_UNIT,
|
ATTR_WEATHER_PRECIPITATION_UNIT,
|
||||||
ATTR_WEATHER_PRESSURE,
|
ATTR_WEATHER_PRESSURE,
|
||||||
@ -63,6 +65,7 @@ class MockWeatherEntity(WeatherEntity):
|
|||||||
self._attr_native_pressure = 10
|
self._attr_native_pressure = 10
|
||||||
self._attr_native_pressure_unit = UnitOfPressure.HPA
|
self._attr_native_pressure_unit = UnitOfPressure.HPA
|
||||||
self._attr_native_temperature = 20
|
self._attr_native_temperature = 20
|
||||||
|
self._attr_native_apparent_temperature = 25
|
||||||
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
|
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
|
||||||
self._attr_native_visibility = 30
|
self._attr_native_visibility = 30
|
||||||
self._attr_native_visibility_unit = UnitOfLength.KILOMETERS
|
self._attr_native_visibility_unit = UnitOfLength.KILOMETERS
|
||||||
@ -85,6 +88,7 @@ class MockWeatherEntityPrecision(WeatherEntity):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self._attr_condition = ATTR_CONDITION_SUNNY
|
self._attr_condition = ATTR_CONDITION_SUNNY
|
||||||
self._attr_native_temperature = 20.3
|
self._attr_native_temperature = 20.3
|
||||||
|
self._attr_native_apparent_temperature = 25.3
|
||||||
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
|
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
|
||||||
self._attr_precision = PRECISION_HALVES
|
self._attr_precision = PRECISION_HALVES
|
||||||
|
|
||||||
@ -153,21 +157,35 @@ async def test_temperature(
|
|||||||
"""Test temperature."""
|
"""Test temperature."""
|
||||||
hass.config.units = unit_system
|
hass.config.units = unit_system
|
||||||
native_value = 38
|
native_value = 38
|
||||||
|
apparent_native_value = 45
|
||||||
state_value = TemperatureConverter.convert(native_value, native_unit, state_unit)
|
state_value = TemperatureConverter.convert(native_value, native_unit, state_unit)
|
||||||
|
apparent_state_value = TemperatureConverter.convert(
|
||||||
|
apparent_native_value, native_unit, state_unit
|
||||||
|
)
|
||||||
|
|
||||||
entity0 = await create_entity(
|
entity0 = await create_entity(
|
||||||
hass, native_temperature=native_value, native_temperature_unit=native_unit
|
hass,
|
||||||
|
native_temperature=native_value,
|
||||||
|
native_temperature_unit=native_unit,
|
||||||
|
native_apparent_temperature=apparent_native_value,
|
||||||
)
|
)
|
||||||
|
|
||||||
state = hass.states.get(entity0.entity_id)
|
state = hass.states.get(entity0.entity_id)
|
||||||
forecast = state.attributes[ATTR_FORECAST][0]
|
forecast = state.attributes[ATTR_FORECAST][0]
|
||||||
|
|
||||||
expected = state_value
|
expected = state_value
|
||||||
|
apparent_expected = apparent_state_value
|
||||||
assert float(state.attributes[ATTR_WEATHER_TEMPERATURE]) == pytest.approx(
|
assert float(state.attributes[ATTR_WEATHER_TEMPERATURE]) == pytest.approx(
|
||||||
expected, rel=0.1
|
expected, rel=0.1
|
||||||
)
|
)
|
||||||
|
assert float(state.attributes[ATTR_WEATHER_APPARENT_TEMPERATURE]) == pytest.approx(
|
||||||
|
apparent_expected, rel=0.1
|
||||||
|
)
|
||||||
assert state.attributes[ATTR_WEATHER_TEMPERATURE_UNIT] == state_unit
|
assert state.attributes[ATTR_WEATHER_TEMPERATURE_UNIT] == state_unit
|
||||||
assert float(forecast[ATTR_FORECAST_TEMP]) == pytest.approx(expected, rel=0.1)
|
assert float(forecast[ATTR_FORECAST_TEMP]) == pytest.approx(expected, rel=0.1)
|
||||||
|
assert float(forecast[ATTR_FORECAST_APPARENT_TEMP]) == pytest.approx(
|
||||||
|
apparent_expected, rel=0.1
|
||||||
|
)
|
||||||
assert float(forecast[ATTR_FORECAST_TEMP_LOW]) == pytest.approx(expected, rel=0.1)
|
assert float(forecast[ATTR_FORECAST_TEMP_LOW]) == pytest.approx(expected, rel=0.1)
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ Call init before using it in your tests to ensure clean test data.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
|
ATTR_FORECAST_NATIVE_APPARENT_TEMP,
|
||||||
ATTR_FORECAST_NATIVE_PRECIPITATION,
|
ATTR_FORECAST_NATIVE_PRECIPITATION,
|
||||||
ATTR_FORECAST_NATIVE_PRESSURE,
|
ATTR_FORECAST_NATIVE_PRESSURE,
|
||||||
ATTR_FORECAST_NATIVE_TEMP,
|
ATTR_FORECAST_NATIVE_TEMP,
|
||||||
@ -46,6 +47,11 @@ class MockWeather(MockEntity, WeatherEntity):
|
|||||||
"""Return the platform temperature."""
|
"""Return the platform temperature."""
|
||||||
return self._handle("native_temperature")
|
return self._handle("native_temperature")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_apparent_temperature(self) -> float | None:
|
||||||
|
"""Return the platform apparent temperature."""
|
||||||
|
return self._handle("native_apparent_temperature")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_temperature_unit(self) -> str | None:
|
def native_temperature_unit(self) -> str | None:
|
||||||
"""Return the unit of measurement for temperature."""
|
"""Return the unit of measurement for temperature."""
|
||||||
@ -195,6 +201,7 @@ class MockWeatherMockForecast(MockWeather):
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
ATTR_FORECAST_NATIVE_TEMP: self.native_temperature,
|
ATTR_FORECAST_NATIVE_TEMP: self.native_temperature,
|
||||||
|
ATTR_FORECAST_NATIVE_APPARENT_TEMP: self.native_apparent_temperature,
|
||||||
ATTR_FORECAST_NATIVE_TEMP_LOW: self.native_temperature,
|
ATTR_FORECAST_NATIVE_TEMP_LOW: self.native_temperature,
|
||||||
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
|
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
|
||||||
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
|
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user