Implement dew point in weather entity component (#95072)
parent
fe71ed8c50
commit
b8de7df609
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -42,6 +42,9 @@
|
|||
"apparent_temperature": {
|
||||
"name": "Apparent temperature"
|
||||
},
|
||||
"dew_point": {
|
||||
"name": "Dew point temperature"
|
||||
},
|
||||
"temperature": {
|
||||
"name": "Temperature"
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue