Implement Apparent temperature in Weather entity component (#95070)

This commit is contained in:
G Johansson 2023-06-22 19:52:14 +02:00 committed by GitHub
parent 38614bc3f0
commit 6ad3b60adf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 1 deletions

View File

@ -30,6 +30,7 @@ from homeassistant.helpers.typing import ConfigType
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
from .const import (
ATTR_WEATHER_APPARENT_TEMPERATURE,
ATTR_WEATHER_HUMIDITY,
ATTR_WEATHER_OZONE,
ATTR_WEATHER_PRECIPITATION_UNIT,
@ -73,6 +74,8 @@ ATTR_FORECAST_PRECIPITATION: Final = "precipitation"
ATTR_FORECAST_PRECIPITATION_PROBABILITY: Final = "precipitation_probability"
ATTR_FORECAST_NATIVE_PRESSURE: Final = "native_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_TEMP: Final = "temperature"
ATTR_FORECAST_NATIVE_TEMP_LOW: Final = "native_templow"
@ -199,6 +202,7 @@ class WeatherEntity(Entity):
_attr_native_pressure: float | 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_unit: str | None = None
_attr_native_visibility: float | None = None
@ -272,6 +276,11 @@ class WeatherEntity(Entity):
return
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
@property
def temperature(self) -> float | None:
@ -600,6 +609,20 @@ class WeatherEntity(Entity):
except (TypeError, ValueError):
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
if (humidity := self.humidity) is not None:
@ -686,6 +709,26 @@ class WeatherEntity(Entity):
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 (
forecast_temp_low := forecast_entry.pop(
ATTR_FORECAST_NATIVE_TEMP_LOW,

View File

@ -22,6 +22,7 @@ ATTR_WEATHER_HUMIDITY = "humidity"
ATTR_WEATHER_OZONE = "ozone"
ATTR_WEATHER_PRESSURE = "pressure"
ATTR_WEATHER_PRESSURE_UNIT = "pressure_unit"
ATTR_WEATHER_APPARENT_TEMPERATURE = "apparent_temperature"
ATTR_WEATHER_TEMPERATURE = "temperature"
ATTR_WEATHER_TEMPERATURE_UNIT = "temperature_unit"
ATTR_WEATHER_VISIBILITY = "visibility"

View File

@ -39,6 +39,9 @@
"pressure_unit": {
"name": "Pressure unit"
},
"apparent_temperature": {
"name": "Apparent temperature"
},
"temperature": {
"name": "Temperature"
},

View File

@ -6,12 +6,14 @@ import pytest
from homeassistant.components.weather import (
ATTR_CONDITION_SUNNY,
ATTR_FORECAST,
ATTR_FORECAST_APPARENT_TEMP,
ATTR_FORECAST_PRECIPITATION,
ATTR_FORECAST_PRESSURE,
ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED,
ATTR_WEATHER_APPARENT_TEMPERATURE,
ATTR_WEATHER_OZONE,
ATTR_WEATHER_PRECIPITATION_UNIT,
ATTR_WEATHER_PRESSURE,
@ -63,6 +65,7 @@ class MockWeatherEntity(WeatherEntity):
self._attr_native_pressure = 10
self._attr_native_pressure_unit = UnitOfPressure.HPA
self._attr_native_temperature = 20
self._attr_native_apparent_temperature = 25
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_native_visibility = 30
self._attr_native_visibility_unit = UnitOfLength.KILOMETERS
@ -85,6 +88,7 @@ class MockWeatherEntityPrecision(WeatherEntity):
super().__init__()
self._attr_condition = ATTR_CONDITION_SUNNY
self._attr_native_temperature = 20.3
self._attr_native_apparent_temperature = 25.3
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_precision = PRECISION_HALVES
@ -153,21 +157,35 @@ async def test_temperature(
"""Test temperature."""
hass.config.units = unit_system
native_value = 38
apparent_native_value = 45
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(
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)
forecast = state.attributes[ATTR_FORECAST][0]
expected = state_value
apparent_expected = apparent_state_value
assert float(state.attributes[ATTR_WEATHER_TEMPERATURE]) == pytest.approx(
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 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)

View File

@ -5,6 +5,7 @@ Call init before using it in your tests to ensure clean test data.
from __future__ import annotations
from homeassistant.components.weather import (
ATTR_FORECAST_NATIVE_APPARENT_TEMP,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_PRESSURE,
ATTR_FORECAST_NATIVE_TEMP,
@ -46,6 +47,11 @@ class MockWeather(MockEntity, WeatherEntity):
"""Return the platform 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
def native_temperature_unit(self) -> str | None:
"""Return the unit of measurement for temperature."""
@ -195,6 +201,7 @@ class MockWeatherMockForecast(MockWeather):
return [
{
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_PRESSURE: self.native_pressure,
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,