diff --git a/homeassistant/components/knx/weather.py b/homeassistant/components/knx/weather.py index 6e71c09501f324..ced33a0457ff24 100644 --- a/homeassistant/components/knx/weather.py +++ b/homeassistant/components/knx/weather.py @@ -6,7 +6,14 @@ from homeassistant import config_entries from homeassistant.components.weather import WeatherEntity -from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, TEMP_CELSIUS, Platform +from homeassistant.const import ( + CONF_ENTITY_CATEGORY, + CONF_NAME, + PRESSURE_PA, + SPEED_METERS_PER_SECOND, + TEMP_CELSIUS, + Platform, +) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType @@ -69,6 +76,8 @@ class KNXWeather(KnxEntity, WeatherEntity): _device: XknxWeather _attr_temperature_unit = TEMP_CELSIUS + _attr_pressure_unit = PRESSURE_PA + _attr_wind_speed_unit = SPEED_METERS_PER_SECOND def __init__(self, xknx: XKNX, config: ConfigType) -> None: """Initialize of a KNX sensor.""" @@ -83,13 +92,8 @@ def temperature(self) -> float | None: @property def pressure(self) -> float | None: - """Return current air pressure.""" - # KNX returns pA - HA requires hPa - return ( - self._device.air_pressure / 100 - if self._device.air_pressure is not None - else None - ) + """Return current air pressure in pA.""" + return self._device.air_pressure @property def condition(self) -> str: @@ -108,10 +112,5 @@ def wind_bearing(self) -> int | None: @property def wind_speed(self) -> float | None: - """Return current wind speed in km/h.""" - # KNX only supports wind speed in m/s - return ( - self._device.wind_speed * 3.6 - if self._device.wind_speed is not None - else None - ) + """Return current wind speed in m/s.""" + return self._device.wind_speed diff --git a/homeassistant/components/met/weather.py b/homeassistant/components/met/weather.py index 53c372030f1918..88ecee0df0a446 100644 --- a/homeassistant/components/met/weather.py +++ b/homeassistant/components/met/weather.py @@ -26,12 +26,9 @@ CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, - LENGTH_INCHES, LENGTH_MILLIMETERS, PRESSURE_HPA, - PRESSURE_INHG, SPEED_KILOMETERS_PER_HOUR, - SPEED_MILES_PER_HOUR, TEMP_CELSIUS, ) from homeassistant.core import HomeAssistant @@ -45,18 +42,8 @@ DataUpdateCoordinator, T, ) -from homeassistant.util.distance import convert as convert_distance -from homeassistant.util.pressure import convert as convert_pressure -from homeassistant.util.speed import convert as convert_speed - -from .const import ( - ATTR_FORECAST_PRECIPITATION, - ATTR_MAP, - CONDITIONS_MAP, - CONF_TRACK_HOME, - DOMAIN, - FORECAST_MAP, -) + +from .const import ATTR_MAP, CONDITIONS_MAP, CONF_TRACK_HOME, DOMAIN, FORECAST_MAP _LOGGER = logging.getLogger(__name__) @@ -133,6 +120,11 @@ def format_condition(condition: str) -> str: class MetWeather(CoordinatorEntity, WeatherEntity): """Implementation of a Met.no weather condition.""" + _attr_temperature_unit = TEMP_CELSIUS + _attr_pressure_unit = PRESSURE_HPA + _attr_wind_speed_unit = SPEED_KILOMETERS_PER_HOUR + _attr_precipitation_unit = LENGTH_MILLIMETERS + def __init__( self, coordinator: DataUpdateCoordinator[T], @@ -196,21 +188,12 @@ def temperature(self) -> float | None: ATTR_MAP[ATTR_WEATHER_TEMPERATURE] ) - @property - def temperature_unit(self) -> str: - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def pressure(self) -> float | None: - """Return the pressure.""" - pressure_hpa = self.coordinator.data.current_weather_data.get( + """Return the pressure in hPa.""" + return self.coordinator.data.current_weather_data.get( ATTR_MAP[ATTR_WEATHER_PRESSURE] ) - if self._is_metric or pressure_hpa is None: - return pressure_hpa - - return round(convert_pressure(pressure_hpa, PRESSURE_HPA, PRESSURE_INHG), 2) @property def humidity(self) -> float | None: @@ -221,17 +204,10 @@ def humidity(self) -> float | None: @property def wind_speed(self) -> float | None: - """Return the wind speed.""" - speed_km_h = self.coordinator.data.current_weather_data.get( + """Return the wind speed in km/h.""" + return self.coordinator.data.current_weather_data.get( ATTR_MAP[ATTR_WEATHER_WIND_SPEED] ) - if self._is_metric or speed_km_h is None: - return speed_km_h - - speed_mi_h = convert_speed( - speed_km_h, SPEED_KILOMETERS_PER_HOUR, SPEED_MILES_PER_HOUR - ) - return int(round(speed_mi_h)) @property def wind_bearing(self) -> float | str | None: @@ -262,14 +238,6 @@ def forecast(self) -> list[Forecast] | None: for k, v in FORECAST_MAP.items() if met_item.get(v) is not None } - if not self._is_metric and ATTR_FORECAST_PRECIPITATION in ha_item: - if ha_item[ATTR_FORECAST_PRECIPITATION] is not None: - precip_inches = convert_distance( - ha_item[ATTR_FORECAST_PRECIPITATION], - LENGTH_MILLIMETERS, - LENGTH_INCHES, - ) - ha_item[ATTR_FORECAST_PRECIPITATION] = round(precip_inches, 2) if ha_item.get(ATTR_FORECAST_CONDITION): ha_item[ATTR_FORECAST_CONDITION] = format_condition( ha_item[ATTR_FORECAST_CONDITION] diff --git a/homeassistant/components/met_eireann/weather.py b/homeassistant/components/met_eireann/weather.py index cbf5c99342a509..32145d1857e76d 100644 --- a/homeassistant/components/met_eireann/weather.py +++ b/homeassistant/components/met_eireann/weather.py @@ -3,7 +3,6 @@ from homeassistant.components.weather import ( ATTR_FORECAST_CONDITION, - ATTR_FORECAST_PRECIPITATION, ATTR_FORECAST_TEMP, ATTR_FORECAST_TIME, WeatherEntity, @@ -13,12 +12,9 @@ CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, - LENGTH_INCHES, LENGTH_MILLIMETERS, PRESSURE_HPA, - PRESSURE_INHG, SPEED_METERS_PER_SECOND, - SPEED_MILES_PER_HOUR, TEMP_CELSIUS, ) from homeassistant.core import HomeAssistant @@ -27,9 +23,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.util import dt as dt_util -from homeassistant.util.distance import convert as convert_distance -from homeassistant.util.pressure import convert as convert_pressure -from homeassistant.util.speed import convert as convert_speed from .const import ATTRIBUTION, CONDITION_MAP, DEFAULT_NAME, DOMAIN, FORECAST_MAP @@ -67,6 +60,11 @@ async def async_setup_entry( class MetEireannWeather(CoordinatorEntity, WeatherEntity): """Implementation of a Met Éireann weather condition.""" + _attr_temperature_unit = TEMP_CELSIUS + _attr_pressure_unit = PRESSURE_HPA + _attr_wind_speed_unit = SPEED_METERS_PER_SECOND + _attr_precipitation_unit = LENGTH_MILLIMETERS + def __init__(self, coordinator, config, is_metric, hourly): """Initialise the platform with a data instance and site.""" super().__init__(coordinator) @@ -113,19 +111,10 @@ def temperature(self): """Return the temperature.""" return self.coordinator.data.current_weather_data.get("temperature") - @property - def temperature_unit(self): - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def pressure(self): - """Return the pressure.""" - pressure_hpa = self.coordinator.data.current_weather_data.get("pressure") - if self._is_metric or pressure_hpa is None: - return pressure_hpa - - return round(convert_pressure(pressure_hpa, PRESSURE_HPA, PRESSURE_INHG), 2) + """Return the pressure in hPa.""" + return self.coordinator.data.current_weather_data.get("pressure") @property def humidity(self): @@ -134,15 +123,8 @@ def humidity(self): @property def wind_speed(self): - """Return the wind speed.""" - speed_m_s = self.coordinator.data.current_weather_data.get("wind_speed") - if self._is_metric or speed_m_s is None: - return speed_m_s - - speed_mi_h = convert_speed( - speed_m_s, SPEED_METERS_PER_SECOND, SPEED_MILES_PER_HOUR - ) - return int(round(speed_mi_h)) + """Return the wind speed in m/s.""" + return self.coordinator.data.current_weather_data.get("wind_speed") @property def wind_bearing(self): @@ -171,13 +153,6 @@ def forecast(self): ha_item = { k: item[v] for k, v in FORECAST_MAP.items() if item.get(v) is not None } - if not self._is_metric and ATTR_FORECAST_PRECIPITATION in ha_item: - precip_inches = convert_distance( - ha_item[ATTR_FORECAST_PRECIPITATION], - LENGTH_MILLIMETERS, - LENGTH_INCHES, - ) - ha_item[ATTR_FORECAST_PRECIPITATION] = round(precip_inches, 2) if ha_item.get(ATTR_FORECAST_CONDITION): ha_item[ATTR_FORECAST_CONDITION] = format_condition( ha_item[ATTR_FORECAST_CONDITION] diff --git a/homeassistant/components/meteo_france/weather.py b/homeassistant/components/meteo_france/weather.py index cca1f6fe684638..e0facb0fe430b2 100644 --- a/homeassistant/components/meteo_france/weather.py +++ b/homeassistant/components/meteo_france/weather.py @@ -13,7 +13,13 @@ WeatherEntity, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_MODE, TEMP_CELSIUS +from homeassistant.const import ( + CONF_MODE, + LENGTH_MILLIMETERS, + PRESSURE_HPA, + SPEED_METERS_PER_SECOND, + TEMP_CELSIUS, +) from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.entity import DeviceInfo @@ -71,6 +77,11 @@ async def async_setup_entry( class MeteoFranceWeather(CoordinatorEntity, WeatherEntity): """Representation of a weather condition.""" + _attr_temperature_unit = TEMP_CELSIUS + _attr_pressure_unit = PRESSURE_HPA + _attr_wind_speed_unit = SPEED_METERS_PER_SECOND + _attr_precipitation_unit = LENGTH_MILLIMETERS + def __init__(self, coordinator: DataUpdateCoordinator, mode: str) -> None: """Initialise the platform with a data instance and station name.""" super().__init__(coordinator) @@ -111,11 +122,6 @@ def temperature(self): """Return the temperature.""" return self.coordinator.data.current_forecast["T"]["value"] - @property - def temperature_unit(self): - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def pressure(self): """Return the pressure.""" @@ -128,9 +134,8 @@ def humidity(self): @property def wind_speed(self): - """Return the wind speed.""" - # convert from API m/s to km/h - return round(self.coordinator.data.current_forecast["wind"]["speed"] * 3.6) + """Return the wind speed in m/s.""" + return self.coordinator.data.current_forecast["wind"]["speed"] @property def wind_bearing(self): diff --git a/homeassistant/components/meteoclimatic/weather.py b/homeassistant/components/meteoclimatic/weather.py index 4faecdaa3ac246..cb71b2ae9bca8e 100644 --- a/homeassistant/components/meteoclimatic/weather.py +++ b/homeassistant/components/meteoclimatic/weather.py @@ -3,7 +3,12 @@ from homeassistant.components.weather import WeatherEntity from homeassistant.config_entries import ConfigEntry -from homeassistant.const import TEMP_CELSIUS +from homeassistant.const import ( + LENGTH_MILLIMETERS, + PRESSURE_HPA, + SPEED_KILOMETERS_PER_HOUR, + TEMP_CELSIUS, +) from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.entity import DeviceInfo @@ -38,6 +43,11 @@ async def async_setup_entry( class MeteoclimaticWeather(CoordinatorEntity, WeatherEntity): """Representation of a weather condition.""" + _attr_temperature_unit = TEMP_CELSIUS + _attr_pressure_unit = PRESSURE_HPA + _attr_wind_speed_unit = SPEED_KILOMETERS_PER_HOUR + _attr_precipitation_unit = LENGTH_MILLIMETERS + def __init__(self, coordinator: DataUpdateCoordinator) -> None: """Initialise the weather platform.""" super().__init__(coordinator) @@ -75,11 +85,6 @@ def temperature(self): """Return the temperature.""" return self.coordinator.data["weather"].temp_current - @property - def temperature_unit(self): - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def humidity(self): """Return the humidity.""" diff --git a/homeassistant/components/metoffice/weather.py b/homeassistant/components/metoffice/weather.py index daf37bcf83f5fb..cce93b6cf273c4 100644 --- a/homeassistant/components/metoffice/weather.py +++ b/homeassistant/components/metoffice/weather.py @@ -9,7 +9,7 @@ WeatherEntity, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import TEMP_CELSIUS +from homeassistant.const import PRESSURE_HPA, SPEED_MILES_PER_HOUR, TEMP_CELSIUS from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -73,6 +73,10 @@ def _get_weather_condition(metoffice_code): class MetOfficeWeather(CoordinatorEntity, WeatherEntity): """Implementation of a Met Office weather condition.""" + _attr_temperature_unit = TEMP_CELSIUS + _attr_pressure_unit = PRESSURE_HPA + _attr_wind_speed_unit = SPEED_MILES_PER_HOUR + def __init__(self, coordinator, hass_data, use_3hourly): """Initialise the platform with a data instance.""" super().__init__(coordinator) @@ -100,11 +104,6 @@ def temperature(self): return self.coordinator.data.now.temperature.value return None - @property - def temperature_unit(self): - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def visibility(self): """Return the platform visibility.""" diff --git a/tests/components/knx/test_weather.py b/tests/components/knx/test_weather.py index 21d80248b97695..a1c58c122615ba 100644 --- a/tests/components/knx/test_weather.py +++ b/tests/components/knx/test_weather.py @@ -1,4 +1,6 @@ """Test KNX weather.""" +import pytest + from homeassistant.components.knx.schema import WeatherSchema from homeassistant.components.weather import ( ATTR_CONDITION_EXCEPTIONAL, @@ -6,7 +8,7 @@ ATTR_CONDITION_SUNNY, ATTR_CONDITION_WINDY, ) -from homeassistant.const import CONF_NAME +from homeassistant.const import CONF_NAME, PRESSURE_HPA, SPEED_KILOMETERS_PER_HOUR from homeassistant.core import HomeAssistant from .conftest import KNXTestKit @@ -14,6 +16,8 @@ async def test_weather(hass: HomeAssistant, knx: KNXTestKit): """Test KNX weather.""" + hass.config.units.wind_speed_unit = SPEED_KILOMETERS_PER_HOUR + hass.config.units.pressure_unit = PRESSURE_HPA await knx.setup_integration( { @@ -85,8 +89,8 @@ async def test_weather(hass: HomeAssistant, knx: KNXTestKit): state = hass.states.get("weather.test") assert state.attributes["temperature"] == 0.4 assert state.attributes["wind_bearing"] == 270 - assert state.attributes["wind_speed"] == 1.4400000000000002 - assert state.attributes["pressure"] == 980.5824 + assert state.attributes["wind_speed"] == pytest.approx(1.44, rel=0.01) + assert state.attributes["pressure"] == pytest.approx(980.5824, rel=0.01) assert state.state is ATTR_CONDITION_SUNNY # update from KNX - set rain alarm diff --git a/tests/components/metoffice/test_weather.py b/tests/components/metoffice/test_weather.py index 158e44ca15b4ff..da0f0ced3a762a 100644 --- a/tests/components/metoffice/test_weather.py +++ b/tests/components/metoffice/test_weather.py @@ -141,7 +141,7 @@ async def test_one_weather_site_running(hass, requests_mock, legacy_patchable_ti assert weather.state == "sunny" assert weather.attributes.get("temperature") == 17 - assert weather.attributes.get("wind_speed") == 9 + assert weather.attributes.get("wind_speed") == 4.02 # 9 mph = 4.02 m/s assert weather.attributes.get("wind_bearing") == "SSE" assert weather.attributes.get("visibility") == "Good - 10-20" assert weather.attributes.get("humidity") == 50 @@ -156,7 +156,9 @@ async def test_one_weather_site_running(hass, requests_mock, legacy_patchable_ti assert weather.attributes.get("forecast")[26]["condition"] == "cloudy" assert weather.attributes.get("forecast")[26]["precipitation_probability"] == 9 assert weather.attributes.get("forecast")[26]["temperature"] == 10 - assert weather.attributes.get("forecast")[26]["wind_speed"] == 4 + assert ( + weather.attributes.get("forecast")[26]["wind_speed"] == 1.79 + ) # 4 mph = 1.79 m/s assert weather.attributes.get("forecast")[26]["wind_bearing"] == "NNE" # Wavertree daily weather platform expected results @@ -165,7 +167,7 @@ async def test_one_weather_site_running(hass, requests_mock, legacy_patchable_ti assert weather.state == "sunny" assert weather.attributes.get("temperature") == 19 - assert weather.attributes.get("wind_speed") == 9 + assert weather.attributes.get("wind_speed") == 4.02 # 9 mph = 4.02 m/s assert weather.attributes.get("wind_bearing") == "SSE" assert weather.attributes.get("visibility") == "Good - 10-20" assert weather.attributes.get("humidity") == 50 @@ -179,7 +181,9 @@ async def test_one_weather_site_running(hass, requests_mock, legacy_patchable_ti assert weather.attributes.get("forecast")[7]["condition"] == "rainy" assert weather.attributes.get("forecast")[7]["precipitation_probability"] == 59 assert weather.attributes.get("forecast")[7]["temperature"] == 13 - assert weather.attributes.get("forecast")[7]["wind_speed"] == 13 + assert ( + weather.attributes.get("forecast")[7]["wind_speed"] == 5.81 + ) # 13 mph = 5.81 m/s assert weather.attributes.get("forecast")[7]["wind_bearing"] == "SE" @@ -239,7 +243,7 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.state == "sunny" assert weather.attributes.get("temperature") == 17 - assert weather.attributes.get("wind_speed") == 9 + assert weather.attributes.get("wind_speed") == 4.02 # 9 mph = 4.02 m/s assert weather.attributes.get("wind_bearing") == "SSE" assert weather.attributes.get("visibility") == "Good - 10-20" assert weather.attributes.get("humidity") == 50 @@ -254,7 +258,9 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.attributes.get("forecast")[18]["condition"] == "clear-night" assert weather.attributes.get("forecast")[18]["precipitation_probability"] == 1 assert weather.attributes.get("forecast")[18]["temperature"] == 9 - assert weather.attributes.get("forecast")[18]["wind_speed"] == 4 + assert ( + weather.attributes.get("forecast")[18]["wind_speed"] == 1.79 + ) # 4 mph = 1.79 m/s assert weather.attributes.get("forecast")[18]["wind_bearing"] == "NW" # Wavertree daily weather platform expected results @@ -263,7 +269,7 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.state == "sunny" assert weather.attributes.get("temperature") == 19 - assert weather.attributes.get("wind_speed") == 9 + assert weather.attributes.get("wind_speed") == 4.02 # 9 mph = 4.02 m/s assert weather.attributes.get("wind_bearing") == "SSE" assert weather.attributes.get("visibility") == "Good - 10-20" assert weather.attributes.get("humidity") == 50 @@ -277,7 +283,9 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.attributes.get("forecast")[7]["condition"] == "rainy" assert weather.attributes.get("forecast")[7]["precipitation_probability"] == 59 assert weather.attributes.get("forecast")[7]["temperature"] == 13 - assert weather.attributes.get("forecast")[7]["wind_speed"] == 13 + assert ( + weather.attributes.get("forecast")[7]["wind_speed"] == 5.81 + ) # 13 mph = 5.81 m/s assert weather.attributes.get("forecast")[7]["wind_bearing"] == "SE" # King's Lynn 3-hourly weather platform expected results @@ -286,7 +294,7 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.state == "sunny" assert weather.attributes.get("temperature") == 14 - assert weather.attributes.get("wind_speed") == 2 + assert weather.attributes.get("wind_speed") == 0.89 # 2 mph = 0.89 m/s assert weather.attributes.get("wind_bearing") == "E" assert weather.attributes.get("visibility") == "Very Good - 20-40" assert weather.attributes.get("humidity") == 60 @@ -301,7 +309,9 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.attributes.get("forecast")[18]["condition"] == "cloudy" assert weather.attributes.get("forecast")[18]["precipitation_probability"] == 9 assert weather.attributes.get("forecast")[18]["temperature"] == 10 - assert weather.attributes.get("forecast")[18]["wind_speed"] == 7 + assert ( + weather.attributes.get("forecast")[18]["wind_speed"] == 3.13 + ) # 7 mph = 3.13 m/s assert weather.attributes.get("forecast")[18]["wind_bearing"] == "SE" # King's Lynn daily weather platform expected results @@ -310,7 +320,7 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.state == "cloudy" assert weather.attributes.get("temperature") == 9 - assert weather.attributes.get("wind_speed") == 4 + assert weather.attributes.get("wind_speed") == 1.79 # 4 mph = 1.79 m/s assert weather.attributes.get("wind_bearing") == "ESE" assert weather.attributes.get("visibility") == "Very Good - 20-40" assert weather.attributes.get("humidity") == 75 @@ -324,5 +334,7 @@ async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_t assert weather.attributes.get("forecast")[5]["condition"] == "cloudy" assert weather.attributes.get("forecast")[5]["precipitation_probability"] == 14 assert weather.attributes.get("forecast")[5]["temperature"] == 11 - assert weather.attributes.get("forecast")[5]["wind_speed"] == 7 + assert ( + weather.attributes.get("forecast")[5]["wind_speed"] == 3.13 + ) # 7 mph = 3.13 m/s assert weather.attributes.get("forecast")[5]["wind_bearing"] == "ESE"