Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Wind Gust speed in Weather entity component #95065

Merged
merged 3 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 45 additions & 0 deletions homeassistant/components/weather/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
ATTR_WEATHER_VISIBILITY,
ATTR_WEATHER_VISIBILITY_UNIT,
ATTR_WEATHER_WIND_BEARING,
ATTR_WEATHER_WIND_GUST_SPEED,
ATTR_WEATHER_WIND_SPEED,
ATTR_WEATHER_WIND_SPEED_UNIT,
DOMAIN,
Expand Down Expand Up @@ -85,6 +86,8 @@
ATTR_FORECAST_TEMP_LOW: Final = "templow"
ATTR_FORECAST_TIME: Final = "datetime"
ATTR_FORECAST_WIND_BEARING: Final = "wind_bearing"
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED: Final = "native_wind_gust_speed"
ATTR_FORECAST_WIND_GUST_SPEED: Final = "wind_gust_speed"
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"
Expand Down Expand Up @@ -138,6 +141,7 @@ class Forecast(TypedDict, total=False):
native_templow: float | None
templow: None
wind_bearing: float | str | None
native_wind_gust_speed: float | None
native_wind_speed: float | None
wind_speed: None
native_dew_point: float | None
Expand Down Expand Up @@ -218,6 +222,7 @@ class WeatherEntity(Entity):
_attr_native_visibility: float | None = None
_attr_native_visibility_unit: str | None = None
_attr_native_precipitation_unit: str | None = None
_attr_native_wind_gust_speed: float | None = None
_attr_native_wind_speed: float | None = None
_attr_native_wind_speed_unit: str | None = None
_attr_native_dew_point: float | None = None
Expand Down Expand Up @@ -418,6 +423,11 @@ def humidity(self) -> float | None:
"""Return the humidity in native units."""
return self._attr_humidity

@property
def native_wind_gust_speed(self) -> float | None:
"""Return the wind gust speed in native units."""
return self._attr_native_wind_gust_speed

@final
@property
def wind_speed(self) -> float | None:
Expand Down Expand Up @@ -686,6 +696,20 @@ def state_attributes(self) -> dict[str, Any]: # noqa: C901
if (wind_bearing := self.wind_bearing) is not None:
data[ATTR_WEATHER_WIND_BEARING] = wind_bearing

if (wind_gust_speed := self.native_wind_gust_speed) is not None:
from_unit = self.native_wind_speed_unit or self._default_wind_speed_unit
to_unit = self._wind_speed_unit
try:
wind_gust_speed_f = float(wind_gust_speed)
value_wind_gust_speed = UNIT_CONVERSIONS[ATTR_WEATHER_WIND_SPEED_UNIT](
wind_gust_speed_f, from_unit, to_unit
)
data[ATTR_WEATHER_WIND_GUST_SPEED] = round(
value_wind_gust_speed, ROUNDING_PRECISION
)
except (TypeError, ValueError):
data[ATTR_WEATHER_WIND_GUST_SPEED] = wind_gust_speed

if (wind_speed := self.native_wind_speed) is not None:
from_unit = self.native_wind_speed_unit or self._default_wind_speed_unit
to_unit = self._wind_speed_unit
Expand Down Expand Up @@ -828,6 +852,27 @@ def state_attributes(self) -> dict[str, Any]: # noqa: C901
ROUNDING_PRECISION,
)

if (
forecast_wind_gust_speed := forecast_entry.pop(
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
None,
)
) is not None:
from_wind_speed_unit = (
self.native_wind_speed_unit or self._default_wind_speed_unit
)
to_wind_speed_unit = self._wind_speed_unit
with suppress(TypeError, ValueError):
forecast_wind_gust_speed_f = float(forecast_wind_gust_speed)
forecast_entry[ATTR_FORECAST_WIND_GUST_SPEED] = round(
UNIT_CONVERSIONS[ATTR_WEATHER_WIND_SPEED_UNIT](
forecast_wind_gust_speed_f,
from_wind_speed_unit,
to_wind_speed_unit,
),
ROUNDING_PRECISION,
)

if (
forecast_wind_speed := forecast_entry.pop(
ATTR_FORECAST_NATIVE_WIND_SPEED,
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/weather/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
ATTR_WEATHER_VISIBILITY = "visibility"
ATTR_WEATHER_VISIBILITY_UNIT = "visibility_unit"
ATTR_WEATHER_WIND_BEARING = "wind_bearing"
ATTR_WEATHER_WIND_GUST_SPEED = "wind_gust_speed"
ATTR_WEATHER_WIND_SPEED = "wind_speed"
ATTR_WEATHER_WIND_SPEED_UNIT = "wind_speed_unit"
ATTR_WEATHER_PRECIPITATION_UNIT = "precipitation_unit"
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/weather/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
"wind_bearing": {
"name": "Wind bearing"
},
"wind_gust_speed": {
"name": "Wind gust speed"
},
"wind_speed": {
"name": "Wind speed"
},
Expand Down
46 changes: 46 additions & 0 deletions tests/components/weather/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_GUST_SPEED,
ATTR_FORECAST_WIND_SPEED,
ATTR_WEATHER_APPARENT_TEMPERATURE,
ATTR_WEATHER_OZONE,
Expand All @@ -25,6 +26,7 @@
ATTR_WEATHER_VISIBILITY,
ATTR_WEATHER_VISIBILITY_UNIT,
ATTR_WEATHER_WIND_BEARING,
ATTR_WEATHER_WIND_GUST_SPEED,
ATTR_WEATHER_WIND_SPEED,
ATTR_WEATHER_WIND_SPEED_UNIT,
ROUNDING_PRECISION,
Expand Down Expand Up @@ -77,6 +79,7 @@ def __init__(self) -> None:
self._attr_native_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_native_visibility = 30
self._attr_native_visibility_unit = UnitOfLength.KILOMETERS
self._attr_native_wind_gust_speed = 10
self._attr_native_wind_speed = 3
self._attr_native_wind_speed_unit = UnitOfSpeed.METERS_PER_SECOND
self._attr_forecast = [
Expand Down Expand Up @@ -373,6 +376,49 @@ async def test_wind_speed(
)


@pytest.mark.parametrize(
"native_unit",
(
UnitOfSpeed.MILES_PER_HOUR,
UnitOfSpeed.KILOMETERS_PER_HOUR,
UnitOfSpeed.METERS_PER_SECOND,
),
)
@pytest.mark.parametrize(
("state_unit", "unit_system"),
(
(UnitOfSpeed.KILOMETERS_PER_HOUR, METRIC_SYSTEM),
(UnitOfSpeed.MILES_PER_HOUR, US_CUSTOMARY_SYSTEM),
),
)
async def test_wind_gust_speed(
hass: HomeAssistant,
enable_custom_integrations: None,
native_unit: str,
state_unit: str,
unit_system,
) -> None:
"""Test wind speed."""
hass.config.units = unit_system
native_value = 10
state_value = SpeedConverter.convert(native_value, native_unit, state_unit)

entity0 = await create_entity(
hass, native_wind_gust_speed=native_value, native_wind_speed_unit=native_unit
)

state = hass.states.get(entity0.entity_id)
forecast = state.attributes[ATTR_FORECAST][0]

expected = state_value
assert float(state.attributes[ATTR_WEATHER_WIND_GUST_SPEED]) == pytest.approx(
expected, rel=1e-2
)
assert float(forecast[ATTR_FORECAST_WIND_GUST_SPEED]) == pytest.approx(
expected, rel=1e-2
)


@pytest.mark.parametrize("native_unit", (None,))
@pytest.mark.parametrize(
("state_unit", "unit_system"),
Expand Down
7 changes: 7 additions & 0 deletions tests/testing_config/custom_components/test/weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ATTR_FORECAST_NATIVE_PRESSURE,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_PRECIPITATION,
ATTR_FORECAST_PRESSURE,
Expand Down Expand Up @@ -80,6 +81,11 @@ def humidity(self) -> float | None:
"""Return the humidity."""
return self._handle("humidity")

@property
def native_wind_gust_speed(self) -> float | None:
"""Return the wind speed."""
return self._handle("native_wind_gust_speed")

@property
def native_wind_speed(self) -> float | None:
"""Return the wind speed."""
Expand Down Expand Up @@ -219,6 +225,7 @@ def forecast(self) -> list[Forecast] | None:
ATTR_FORECAST_NATIVE_DEW_POINT: self.native_dew_point,
ATTR_FORECAST_CLOUD_COVERAGE: self.cloud_coverage,
ATTR_FORECAST_NATIVE_PRESSURE: self.native_pressure,
ATTR_FORECAST_NATIVE_WIND_GUST_SPEED: self.native_wind_gust_speed,
ATTR_FORECAST_NATIVE_WIND_SPEED: self.native_wind_speed,
ATTR_FORECAST_WIND_BEARING: self.wind_bearing,
ATTR_FORECAST_NATIVE_PRECIPITATION: self._values.get(
Expand Down