Fix wind speed SMHI (#72999)

This commit is contained in:
G Johansson 2022-06-28 01:50:06 +02:00 committed by GitHub
parent b2c84a4c4a
commit 2f0fe0df82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 26 deletions

View File

@ -2,9 +2,10 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from collections.abc import Mapping
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
from typing import Final from typing import Any, Final
import aiohttp import aiohttp
import async_timeout import async_timeout
@ -27,10 +28,14 @@ from homeassistant.components.weather import (
ATTR_CONDITION_WINDY, ATTR_CONDITION_WINDY,
ATTR_CONDITION_WINDY_VARIANT, ATTR_CONDITION_WINDY_VARIANT,
ATTR_FORECAST_CONDITION, ATTR_FORECAST_CONDITION,
ATTR_FORECAST_PRECIPITATION, ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_TEMP, ATTR_FORECAST_NATIVE_PRESSURE,
ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_TIME, ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
ROUNDING_PRECISION,
Forecast, Forecast,
WeatherEntity, WeatherEntity,
) )
@ -41,6 +46,8 @@ from homeassistant.const import (
CONF_NAME, CONF_NAME,
LENGTH_KILOMETERS, LENGTH_KILOMETERS,
LENGTH_MILLIMETERS, LENGTH_MILLIMETERS,
PRESSURE_HPA,
SPEED_METERS_PER_SECOND,
TEMP_CELSIUS, TEMP_CELSIUS,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -49,7 +56,7 @@ from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_call_later from homeassistant.helpers.event import async_call_later
from homeassistant.util import Throttle, slugify from homeassistant.util import Throttle, slugify, speed as speed_util
from .const import ( from .const import (
ATTR_SMHI_CLOUDINESS, ATTR_SMHI_CLOUDINESS,
@ -112,9 +119,11 @@ class SmhiWeather(WeatherEntity):
"""Representation of a weather entity.""" """Representation of a weather entity."""
_attr_attribution = "Swedish weather institute (SMHI)" _attr_attribution = "Swedish weather institute (SMHI)"
_attr_temperature_unit = TEMP_CELSIUS _attr_native_temperature_unit = TEMP_CELSIUS
_attr_visibility_unit = LENGTH_KILOMETERS _attr_native_visibility_unit = LENGTH_KILOMETERS
_attr_precipitation_unit = LENGTH_MILLIMETERS _attr_native_precipitation_unit = LENGTH_MILLIMETERS
_attr_native_wind_speed_unit = SPEED_METERS_PER_SECOND
_attr_native_pressure_unit = PRESSURE_HPA
def __init__( def __init__(
self, self,
@ -139,7 +148,23 @@ class SmhiWeather(WeatherEntity):
configuration_url="http://opendata.smhi.se/apidocs/metfcst/parameters.html", configuration_url="http://opendata.smhi.se/apidocs/metfcst/parameters.html",
) )
self._attr_condition = None self._attr_condition = None
self._attr_temperature = None self._attr_native_temperature = None
@property
def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return additional attributes."""
if self._forecasts:
wind_gust = speed_util.convert(
self._forecasts[0].wind_gust,
SPEED_METERS_PER_SECOND,
self._wind_speed_unit,
)
return {
ATTR_SMHI_CLOUDINESS: self._forecasts[0].cloudiness,
ATTR_SMHI_WIND_GUST_SPEED: round(wind_gust, ROUNDING_PRECISION),
ATTR_SMHI_THUNDER_PROBABILITY: self._forecasts[0].thunder,
}
return None
@Throttle(MIN_TIME_BETWEEN_UPDATES) @Throttle(MIN_TIME_BETWEEN_UPDATES)
async def async_update(self) -> None: async def async_update(self) -> None:
@ -156,13 +181,12 @@ class SmhiWeather(WeatherEntity):
return return
if self._forecasts: if self._forecasts:
self._attr_temperature = self._forecasts[0].temperature self._attr_native_temperature = self._forecasts[0].temperature
self._attr_humidity = self._forecasts[0].humidity self._attr_humidity = self._forecasts[0].humidity
# Convert from m/s to km/h self._attr_native_wind_speed = self._forecasts[0].wind_speed
self._attr_wind_speed = round(self._forecasts[0].wind_speed * 18 / 5)
self._attr_wind_bearing = self._forecasts[0].wind_direction self._attr_wind_bearing = self._forecasts[0].wind_direction
self._attr_visibility = self._forecasts[0].horizontal_visibility self._attr_native_visibility = self._forecasts[0].horizontal_visibility
self._attr_pressure = self._forecasts[0].pressure self._attr_native_pressure = self._forecasts[0].pressure
self._attr_condition = next( self._attr_condition = next(
( (
k k
@ -171,12 +195,6 @@ class SmhiWeather(WeatherEntity):
), ),
None, None,
) )
self._attr_extra_state_attributes = {
ATTR_SMHI_CLOUDINESS: self._forecasts[0].cloudiness,
# Convert from m/s to km/h
ATTR_SMHI_WIND_GUST_SPEED: round(self._forecasts[0].wind_gust * 18 / 5),
ATTR_SMHI_THUNDER_PROBABILITY: self._forecasts[0].thunder,
}
async def retry_update(self, _: datetime) -> None: async def retry_update(self, _: datetime) -> None:
"""Retry refresh weather forecast.""" """Retry refresh weather forecast."""
@ -200,10 +218,13 @@ class SmhiWeather(WeatherEntity):
data.append( data.append(
{ {
ATTR_FORECAST_TIME: forecast.valid_time.isoformat(), ATTR_FORECAST_TIME: forecast.valid_time.isoformat(),
ATTR_FORECAST_TEMP: forecast.temperature_max, ATTR_FORECAST_NATIVE_TEMP: forecast.temperature_max,
ATTR_FORECAST_TEMP_LOW: forecast.temperature_min, ATTR_FORECAST_NATIVE_TEMP_LOW: forecast.temperature_min,
ATTR_FORECAST_PRECIPITATION: round(forecast.total_precipitation, 1), ATTR_FORECAST_NATIVE_PRECIPITATION: forecast.total_precipitation,
ATTR_FORECAST_CONDITION: condition, ATTR_FORECAST_CONDITION: condition,
ATTR_FORECAST_NATIVE_PRESSURE: forecast.pressure,
ATTR_FORECAST_WIND_BEARING: forecast.wind_direction,
ATTR_FORECAST_NATIVE_WIND_SPEED: forecast.wind_speed,
} }
) )

View File

@ -16,18 +16,24 @@ from homeassistant.components.weather import (
ATTR_FORECAST, ATTR_FORECAST,
ATTR_FORECAST_CONDITION, ATTR_FORECAST_CONDITION,
ATTR_FORECAST_PRECIPITATION, ATTR_FORECAST_PRECIPITATION,
ATTR_FORECAST_PRESSURE,
ATTR_FORECAST_TEMP, ATTR_FORECAST_TEMP,
ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_TEMP_LOW,
ATTR_FORECAST_TIME, ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
ATTR_FORECAST_WIND_SPEED,
ATTR_WEATHER_HUMIDITY, ATTR_WEATHER_HUMIDITY,
ATTR_WEATHER_PRESSURE, ATTR_WEATHER_PRESSURE,
ATTR_WEATHER_TEMPERATURE, ATTR_WEATHER_TEMPERATURE,
ATTR_WEATHER_VISIBILITY, ATTR_WEATHER_VISIBILITY,
ATTR_WEATHER_WIND_BEARING, ATTR_WEATHER_WIND_BEARING,
ATTR_WEATHER_WIND_SPEED, ATTR_WEATHER_WIND_SPEED,
ATTR_WEATHER_WIND_SPEED_UNIT,
DOMAIN as WEATHER_DOMAIN,
) )
from homeassistant.const import ATTR_ATTRIBUTION, STATE_UNKNOWN from homeassistant.const import ATTR_ATTRIBUTION, SPEED_METERS_PER_SECOND, STATE_UNKNOWN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
from . import ENTITY_ID, TEST_CONFIG from . import ENTITY_ID, TEST_CONFIG
@ -58,13 +64,13 @@ async def test_setup_hass(
assert state.state == "sunny" assert state.state == "sunny"
assert state.attributes[ATTR_SMHI_CLOUDINESS] == 50 assert state.attributes[ATTR_SMHI_CLOUDINESS] == 50
assert state.attributes[ATTR_SMHI_THUNDER_PROBABILITY] == 33 assert state.attributes[ATTR_SMHI_THUNDER_PROBABILITY] == 33
assert state.attributes[ATTR_SMHI_WIND_GUST_SPEED] == 17 assert state.attributes[ATTR_SMHI_WIND_GUST_SPEED] == 16.92
assert state.attributes[ATTR_ATTRIBUTION].find("SMHI") >= 0 assert state.attributes[ATTR_ATTRIBUTION].find("SMHI") >= 0
assert state.attributes[ATTR_WEATHER_HUMIDITY] == 55 assert state.attributes[ATTR_WEATHER_HUMIDITY] == 55
assert state.attributes[ATTR_WEATHER_PRESSURE] == 1024 assert state.attributes[ATTR_WEATHER_PRESSURE] == 1024
assert state.attributes[ATTR_WEATHER_TEMPERATURE] == 17 assert state.attributes[ATTR_WEATHER_TEMPERATURE] == 17
assert state.attributes[ATTR_WEATHER_VISIBILITY] == 50 assert state.attributes[ATTR_WEATHER_VISIBILITY] == 50
assert state.attributes[ATTR_WEATHER_WIND_SPEED] == 7 assert state.attributes[ATTR_WEATHER_WIND_SPEED] == 6.84
assert state.attributes[ATTR_WEATHER_WIND_BEARING] == 134 assert state.attributes[ATTR_WEATHER_WIND_BEARING] == 134
assert len(state.attributes["forecast"]) == 4 assert len(state.attributes["forecast"]) == 4
@ -74,6 +80,9 @@ async def test_setup_hass(
assert forecast[ATTR_FORECAST_TEMP_LOW] == 6 assert forecast[ATTR_FORECAST_TEMP_LOW] == 6
assert forecast[ATTR_FORECAST_PRECIPITATION] == 0 assert forecast[ATTR_FORECAST_PRECIPITATION] == 0
assert forecast[ATTR_FORECAST_CONDITION] == "partlycloudy" assert forecast[ATTR_FORECAST_CONDITION] == "partlycloudy"
assert forecast[ATTR_FORECAST_PRESSURE] == 1026
assert forecast[ATTR_FORECAST_WIND_BEARING] == 203
assert forecast[ATTR_FORECAST_WIND_SPEED] == 6.12
async def test_properties_no_data(hass: HomeAssistant) -> None: async def test_properties_no_data(hass: HomeAssistant) -> None:
@ -305,3 +314,35 @@ def test_condition_class():
assert get_condition(23) == "snowy-rainy" assert get_condition(23) == "snowy-rainy"
# 24. Heavy sleet # 24. Heavy sleet
assert get_condition(24) == "snowy-rainy" assert get_condition(24) == "snowy-rainy"
async def test_custom_speed_unit(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, api_response: str
) -> None:
"""Test Wind Gust speed with custom unit."""
uri = APIURL_TEMPLATE.format(TEST_CONFIG["longitude"], TEST_CONFIG["latitude"])
aioclient_mock.get(uri, text=api_response)
entry = MockConfigEntry(domain="smhi", data=TEST_CONFIG)
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state
assert state.name == "test"
assert state.attributes[ATTR_SMHI_WIND_GUST_SPEED] == 16.92
entity_reg = er.async_get(hass)
entity_reg.async_update_entity_options(
state.entity_id,
WEATHER_DOMAIN,
{ATTR_WEATHER_WIND_SPEED_UNIT: SPEED_METERS_PER_SECOND},
)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state.attributes[ATTR_SMHI_WIND_GUST_SPEED] == 4.7