Implement dew point in weather entity component (#95072)

pull/95083/head
G Johansson 2023-06-22 21:34:23 +02:00 committed by GitHub
parent fe71ed8c50
commit b8de7df609
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 1 deletions

View File

@ -31,6 +31,7 @@ from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
from .const import (
ATTR_WEATHER_APPARENT_TEMPERATURE,
ATTR_WEATHER_DEW_POINT,
ATTR_WEATHER_HUMIDITY,
ATTR_WEATHER_OZONE,
ATTR_WEATHER_PRECIPITATION_UNIT,
@ -84,6 +85,8 @@ ATTR_FORECAST_TIME: Final = "datetime"
ATTR_FORECAST_WIND_BEARING: Final = "wind_bearing"
ATTR_FORECAST_NATIVE_WIND_SPEED: Final = "native_wind_speed"
ATTR_FORECAST_WIND_SPEED: Final = "wind_speed"
ATTR_FORECAST_NATIVE_DEW_POINT: Final = "native_dew_point"
ATTR_FORECAST_DEW_POINT: Final = "dew_point"
ENTITY_ID_FORMAT = DOMAIN + ".{}"
@ -132,6 +135,7 @@ class Forecast(TypedDict, total=False):
wind_bearing: float | str | None
native_wind_speed: float | None
wind_speed: None
native_dew_point: float | None
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
@ -210,6 +214,7 @@ class WeatherEntity(Entity):
_attr_native_precipitation_unit: str | None = None
_attr_native_wind_speed: float | None = None
_attr_native_wind_speed_unit: str | None = None
_attr_native_dew_point: float | None = None
_weather_option_temperature_unit: str | None = None
_weather_option_pressure_unit: str | None = None
@ -306,6 +311,11 @@ class WeatherEntity(Entity):
return self._attr_native_temperature_unit
@property
def native_dew_point(self) -> float | None:
"""Return the dew point temperature in native units."""
return self._attr_native_dew_point
@final
@property
def temperature_unit(self) -> str | None:
@ -623,6 +633,20 @@ class WeatherEntity(Entity):
except (TypeError, ValueError):
data[ATTR_WEATHER_APPARENT_TEMPERATURE] = apparent_temperature
if (dew_point := self.native_dew_point) is not None:
from_unit = self.native_temperature_unit or self._default_temperature_unit
to_unit = self._temperature_unit
try:
dew_point_f = float(dew_point)
value_dew_point = UNIT_CONVERSIONS[ATTR_WEATHER_TEMPERATURE_UNIT](
dew_point_f, from_unit, to_unit
)
data[ATTR_WEATHER_DEW_POINT] = round_temperature(
value_dew_point, precision
)
except (TypeError, ValueError):
data[ATTR_WEATHER_DEW_POINT] = dew_point
data[ATTR_WEATHER_TEMPERATURE_UNIT] = self._temperature_unit
if (humidity := self.humidity) is not None:
@ -749,6 +773,26 @@ class WeatherEntity(Entity):
value_temp_low, precision
)
if (
forecast_dew_point := forecast_entry.pop(
ATTR_FORECAST_NATIVE_DEW_POINT,
None,
)
) is not None:
with suppress(TypeError, ValueError):
forecast_dew_point_f = float(forecast_dew_point)
value_dew_point = UNIT_CONVERSIONS[
ATTR_WEATHER_TEMPERATURE_UNIT
](
forecast_dew_point_f,
from_temp_unit,
to_temp_unit,
)
forecast_entry[ATTR_FORECAST_DEW_POINT] = round_temperature(
value_dew_point, precision
)
if (
forecast_pressure := forecast_entry.pop(
ATTR_FORECAST_NATIVE_PRESSURE,

View File

@ -20,6 +20,7 @@ from homeassistant.util.unit_conversion import (
ATTR_WEATHER_HUMIDITY = "humidity"
ATTR_WEATHER_OZONE = "ozone"
ATTR_WEATHER_DEW_POINT = "dew_point"
ATTR_WEATHER_PRESSURE = "pressure"
ATTR_WEATHER_PRESSURE_UNIT = "pressure_unit"
ATTR_WEATHER_APPARENT_TEMPERATURE = "apparent_temperature"

View File

@ -42,6 +42,9 @@
"apparent_temperature": {
"name": "Apparent temperature"
},
"dew_point": {
"name": "Dew point temperature"
},
"temperature": {
"name": "Temperature"
},

View File

@ -7,6 +7,7 @@ from homeassistant.components.weather import (
ATTR_CONDITION_SUNNY,
ATTR_FORECAST,
ATTR_FORECAST_APPARENT_TEMP,
ATTR_FORECAST_DEW_POINT,
ATTR_FORECAST_PRECIPITATION,
ATTR_FORECAST_PRESSURE,
ATTR_FORECAST_TEMP,
@ -30,6 +31,7 @@ from homeassistant.components.weather import (
WeatherEntity,
round_temperature,
)
from homeassistant.components.weather.const import ATTR_WEATHER_DEW_POINT
from homeassistant.const import (
ATTR_FRIENDLY_NAME,
PRECISION_HALVES,
@ -66,6 +68,7 @@ class MockWeatherEntity(WeatherEntity):
self._attr_native_pressure_unit = UnitOfPressure.HPA
self._attr_native_temperature = 20
self._attr_native_apparent_temperature = 25
self._attr_native_dew_point = 2
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_native_visibility = 30
self._attr_native_visibility_unit = UnitOfLength.KILOMETERS
@ -76,6 +79,7 @@ class MockWeatherEntity(WeatherEntity):
datetime=datetime(2022, 6, 20, 20, 00, 00),
native_precipitation=1,
native_temperature=20,
native_dew_point=2,
)
]
@ -89,6 +93,7 @@ class MockWeatherEntityPrecision(WeatherEntity):
self._attr_condition = ATTR_CONDITION_SUNNY
self._attr_native_temperature = 20.3
self._attr_native_apparent_temperature = 25.3
self._attr_native_dew_point = 2.3
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_precision = PRECISION_HALVES
@ -158,16 +163,22 @@ async def test_temperature(
hass.config.units = unit_system
native_value = 38
apparent_native_value = 45
dew_point_native_value = 32
state_value = TemperatureConverter.convert(native_value, native_unit, state_unit)
apparent_state_value = TemperatureConverter.convert(
apparent_native_value, native_unit, state_unit
)
state_value = TemperatureConverter.convert(native_value, native_unit, state_unit)
dew_point_state_value = TemperatureConverter.convert(
dew_point_native_value, native_unit, state_unit
)
entity0 = await create_entity(
hass,
native_temperature=native_value,
native_temperature_unit=native_unit,
native_apparent_temperature=apparent_native_value,
native_dew_point=dew_point_native_value,
)
state = hass.states.get(entity0.entity_id)
@ -175,17 +186,24 @@ async def test_temperature(
expected = state_value
apparent_expected = apparent_state_value
dew_point_expected = dew_point_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 float(state.attributes[ATTR_WEATHER_DEW_POINT]) == pytest.approx(
dew_point_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_DEW_POINT]) == pytest.approx(
dew_point_expected, rel=0.1
)
assert float(forecast[ATTR_FORECAST_TEMP_LOW]) == pytest.approx(expected, rel=0.1)
@ -207,21 +225,33 @@ async def test_temperature_no_unit(
"""Test temperature when the entity does not declare a native unit."""
hass.config.units = unit_system
native_value = 38
dew_point_native_value = 32
state_value = native_value
dew_point_state_value = dew_point_native_value
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_dew_point=dew_point_native_value,
)
state = hass.states.get(entity0.entity_id)
forecast = state.attributes[ATTR_FORECAST][0]
expected = state_value
dew_point_expected = dew_point_state_value
assert float(state.attributes[ATTR_WEATHER_TEMPERATURE]) == pytest.approx(
expected, rel=0.1
)
assert float(state.attributes[ATTR_WEATHER_DEW_POINT]) == pytest.approx(
dew_point_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_DEW_POINT]) == pytest.approx(
dew_point_expected, rel=0.1
)
assert float(forecast[ATTR_FORECAST_TEMP_LOW]) == pytest.approx(expected, rel=0.1)
@ -943,7 +973,9 @@ async def test_precision_for_temperature(hass: HomeAssistant) -> None:
assert weather.condition == ATTR_CONDITION_SUNNY
assert weather.native_temperature == 20.3
assert weather.native_dew_point == 2.3
assert weather._temperature_unit == UnitOfTemperature.CELSIUS
assert weather.precision == PRECISION_HALVES
assert weather.state_attributes[ATTR_WEATHER_TEMPERATURE] == 20.5
assert weather.state_attributes[ATTR_WEATHER_DEW_POINT] == 2.5

View File

@ -6,6 +6,7 @@ from __future__ import annotations
from homeassistant.components.weather import (
ATTR_FORECAST_NATIVE_APPARENT_TEMP,
ATTR_FORECAST_NATIVE_DEW_POINT,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_PRESSURE,
ATTR_FORECAST_NATIVE_TEMP,
@ -52,6 +53,11 @@ class MockWeather(MockEntity, WeatherEntity):
"""Return the platform apparent temperature."""
return self._handle("native_apparent_temperature")
@property
def native_dew_point(self) -> float | None:
"""Return the platform dewpoint temperature."""
return self._handle("native_dew_point")
@property
def native_temperature_unit(self) -> str | None:
"""Return the unit of measurement for temperature."""
@ -203,6 +209,7 @@ class MockWeatherMockForecast(MockWeather):
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_DEW_POINT: self.native_dew_point,
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
ATTR_FORECAST_WIND_BEARING: self.wind_bearing,