diff --git a/homeassistant/components/ipma/config_flow.py b/homeassistant/components/ipma/config_flow.py index d1532066f68..3811d30bfbe 100644 --- a/homeassistant/components/ipma/config_flow.py +++ b/homeassistant/components/ipma/config_flow.py @@ -2,10 +2,11 @@ import voluptuous as vol from homeassistant import config_entries -from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME +from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE, CONF_NAME import homeassistant.helpers.config_validation as cv from .const import DOMAIN, HOME_LOCATION_NAME +from .weather import FORECAST_MODE @config_entries.HANDLERS.register(DOMAIN) @@ -49,6 +50,7 @@ class IpmaFlowHandler(config_entries.ConfigFlow): vol.Required(CONF_NAME, default=name): str, vol.Required(CONF_LATITUDE, default=latitude): cv.latitude, vol.Required(CONF_LONGITUDE, default=longitude): cv.longitude, + vol.Required(CONF_MODE, default="daily"): vol.In(FORECAST_MODE), } ), errors=self._errors, diff --git a/homeassistant/components/ipma/strings.json b/homeassistant/components/ipma/strings.json index f22d1b62fe4..ea8b9edcc86 100644 --- a/homeassistant/components/ipma/strings.json +++ b/homeassistant/components/ipma/strings.json @@ -8,7 +8,8 @@ "data": { "name": "Name", "latitude": "Latitude", - "longitude": "Longitude" + "longitude": "Longitude", + "mode": "Mode" } } }, diff --git a/homeassistant/components/ipma/weather.py b/homeassistant/components/ipma/weather.py index 7b07406d007..1fce3922b58 100644 --- a/homeassistant/components/ipma/weather.py +++ b/homeassistant/components/ipma/weather.py @@ -13,13 +13,22 @@ from homeassistant.components.weather import ( ATTR_FORECAST_TEMP, ATTR_FORECAST_TEMP_LOW, ATTR_FORECAST_TIME, + ATTR_FORECAST_WIND_BEARING, + ATTR_FORECAST_WIND_SPEED, PLATFORM_SCHEMA, WeatherEntity, ) -from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, TEMP_CELSIUS +from homeassistant.const import ( + CONF_LATITUDE, + CONF_LONGITUDE, + CONF_MODE, + CONF_NAME, + TEMP_CELSIUS, +) from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.util import Throttle +from homeassistant.util.dt import now, parse_datetime _LOGGER = logging.getLogger(__name__) @@ -44,11 +53,14 @@ CONDITION_CLASSES = { "exceptional": [], } +FORECAST_MODE = ["hourly", "daily"] + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_LATITUDE): cv.latitude, vol.Optional(CONF_LONGITUDE): cv.longitude, + vol.Optional(CONF_MODE, default="daily"): vol.In(FORECAST_MODE), } ) @@ -96,10 +108,12 @@ async def async_get_location(hass, api, latitude, longitude): location = await Location.get(api, float(latitude), float(longitude)) _LOGGER.debug( - "Initializing for coordinates %s, %s -> station %s", + "Initializing for coordinates %s, %s -> station %s (%d, %d)", latitude, longitude, location.station, + location.id_station, + location.global_id_local, ) return location @@ -112,6 +126,7 @@ class IPMAWeather(WeatherEntity): """Initialise the platform with a data instance and station name.""" self._api = api self._location_name = config.get(CONF_NAME, location.name) + self._mode = config.get(CONF_MODE) self._location = location self._observation = None self._forecast = None @@ -129,7 +144,7 @@ class IPMAWeather(WeatherEntity): _LOGGER.warning("Could not update weather observation") if new_forecast: - self._forecast = [f for f in new_forecast if f.forecasted_hours == 24] + self._forecast = new_forecast else: _LOGGER.warning("Could not update weather forecast") @@ -220,22 +235,57 @@ class IPMAWeather(WeatherEntity): if not self._forecast: return [] - fcdata_out = [ - { - ATTR_FORECAST_TIME: data_in.forecast_date, - ATTR_FORECAST_CONDITION: next( - ( - k - for k, v in CONDITION_CLASSES.items() - if int(data_in.weather_type) in v + if self._mode == "hourly": + forecast_filtered = [ + x + for x in self._forecast + if x.forecasted_hours == 1 + and parse_datetime(x.forecast_date) + > (now().utcnow() - timedelta(hours=1)) + ] + + fcdata_out = [ + { + ATTR_FORECAST_TIME: data_in.forecast_date, + ATTR_FORECAST_CONDITION: next( + ( + k + for k, v in CONDITION_CLASSES.items() + if int(data_in.weather_type) in v + ), + None, ), - None, - ), - ATTR_FORECAST_TEMP_LOW: data_in.min_temperature, - ATTR_FORECAST_TEMP: data_in.max_temperature, - ATTR_FORECAST_PRECIPITATION: data_in.precipitation_probability, - } - for data_in in self._forecast - ] + ATTR_FORECAST_TEMP: float(data_in.feels_like_temperature), + ATTR_FORECAST_PRECIPITATION: ( + data_in.precipitation_probability + if float(data_in.precipitation_probability) >= 0 + else None + ), + ATTR_FORECAST_WIND_SPEED: data_in.wind_strength, + ATTR_FORECAST_WIND_BEARING: data_in.wind_direction, + } + for data_in in forecast_filtered + ] + else: + forecast_filtered = [f for f in self._forecast if f.forecasted_hours == 24] + fcdata_out = [ + { + ATTR_FORECAST_TIME: data_in.forecast_date, + ATTR_FORECAST_CONDITION: next( + ( + k + for k, v in CONDITION_CLASSES.items() + if int(data_in.weather_type) in v + ), + None, + ), + ATTR_FORECAST_TEMP_LOW: data_in.min_temperature, + ATTR_FORECAST_TEMP: data_in.max_temperature, + ATTR_FORECAST_PRECIPITATION: data_in.precipitation_probability, + ATTR_FORECAST_WIND_SPEED: data_in.wind_strength, + ATTR_FORECAST_WIND_BEARING: data_in.wind_direction, + } + for data_in in forecast_filtered + ] return fcdata_out diff --git a/tests/components/ipma/test_weather.py b/tests/components/ipma/test_weather.py index ead4654cba2..7a6e1160f24 100644 --- a/tests/components/ipma/test_weather.py +++ b/tests/components/ipma/test_weather.py @@ -4,6 +4,14 @@ from unittest.mock import patch from homeassistant.components import weather from homeassistant.components.weather import ( + ATTR_FORECAST, + ATTR_FORECAST_CONDITION, + ATTR_FORECAST_PRECIPITATION, + ATTR_FORECAST_TEMP, + ATTR_FORECAST_TEMP_LOW, + ATTR_FORECAST_TIME, + ATTR_FORECAST_WIND_BEARING, + ATTR_FORECAST_WIND_SPEED, ATTR_WEATHER_HUMIDITY, ATTR_WEATHER_PRESSURE, ATTR_WEATHER_TEMPERATURE, @@ -12,6 +20,7 @@ from homeassistant.components.weather import ( DOMAIN as WEATHER_DOMAIN, ) from homeassistant.setup import async_setup_component +from homeassistant.util.dt import now from tests.common import MockConfigEntry, mock_coro @@ -71,16 +80,16 @@ class MockLocation: "2020-01-15T07:51:00", 9, "S", - None, + "10", ), Forecast( "7.7", - "2020-01-15T02:00:00", + now().utcnow().strftime("%Y-%m-%dT%H:%M:%S"), 1, "86.9", None, None, - "-99.0", + "80.0", 10.6, "2020-01-15T07:51:00", 10, @@ -122,7 +131,9 @@ async def test_setup_configuration(hass): return_value=mock_coro(MockLocation()), ): assert await async_setup_component( - hass, weather.DOMAIN, {"weather": {"name": "HomeTown", "platform": "ipma"}} + hass, + weather.DOMAIN, + {"weather": {"name": "HomeTown", "platform": "ipma", "mode": "hourly"}}, ) await hass.async_block_till_done() @@ -158,3 +169,53 @@ async def test_setup_config_flow(hass): assert data.get(ATTR_WEATHER_WIND_SPEED) == 3.94 assert data.get(ATTR_WEATHER_WIND_BEARING) == "NW" assert state.attributes.get("friendly_name") == "HomeTown" + + +async def test_daily_forecast(hass): + """Test for successfully getting daily forecast.""" + with patch( + "homeassistant.components.ipma.weather.async_get_location", + return_value=mock_coro(MockLocation()), + ): + assert await async_setup_component( + hass, + weather.DOMAIN, + {"weather": {"name": "HomeTown", "platform": "ipma", "mode": "daily"}}, + ) + await hass.async_block_till_done() + + state = hass.states.get("weather.hometown") + assert state.state == "rainy" + + forecast = state.attributes.get(ATTR_FORECAST)[0] + assert forecast.get(ATTR_FORECAST_TIME) == "2020-01-15T00:00:00" + assert forecast.get(ATTR_FORECAST_CONDITION) == "rainy" + assert forecast.get(ATTR_FORECAST_TEMP) == 16.2 + assert forecast.get(ATTR_FORECAST_TEMP_LOW) == 10.6 + assert forecast.get(ATTR_FORECAST_PRECIPITATION) == "100.0" + assert forecast.get(ATTR_FORECAST_WIND_SPEED) == "10" + assert forecast.get(ATTR_FORECAST_WIND_BEARING) == "S" + + +async def test_hourly_forecast(hass): + """Test for successfully getting daily forecast.""" + with patch( + "homeassistant.components.ipma.weather.async_get_location", + return_value=mock_coro(MockLocation()), + ): + assert await async_setup_component( + hass, + weather.DOMAIN, + {"weather": {"name": "HomeTown", "platform": "ipma", "mode": "hourly"}}, + ) + await hass.async_block_till_done() + + state = hass.states.get("weather.hometown") + assert state.state == "rainy" + + forecast = state.attributes.get(ATTR_FORECAST)[0] + assert forecast.get(ATTR_FORECAST_CONDITION) == "rainy" + assert forecast.get(ATTR_FORECAST_TEMP) == 7.7 + assert forecast.get(ATTR_FORECAST_PRECIPITATION) == "80.0" + assert forecast.get(ATTR_FORECAST_WIND_SPEED) == "32.7" + assert forecast.get(ATTR_FORECAST_WIND_BEARING) == "S"