Retry on unavailable IPMA api (#78332)
Co-authored-by: J. Nick Koston <nick@koston.org>pull/78410/head
parent
6a197332c7
commit
7b83807baa
|
@ -1,19 +1,61 @@
|
||||||
"""Component for the Portuguese weather service - IPMA."""
|
"""Component for the Portuguese weather service - IPMA."""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
|
from pyipma import IPMAException
|
||||||
|
from pyipma.api import IPMA_API
|
||||||
|
from pyipma.location import Location
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
from .config_flow import IpmaFlowHandler # noqa: F401
|
from .config_flow import IpmaFlowHandler # noqa: F401
|
||||||
from .const import DOMAIN # noqa: F401
|
from .const import DATA_API, DATA_LOCATION, DOMAIN
|
||||||
|
|
||||||
DEFAULT_NAME = "ipma"
|
DEFAULT_NAME = "ipma"
|
||||||
|
|
||||||
PLATFORMS = [Platform.WEATHER]
|
PLATFORMS = [Platform.WEATHER]
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
||||||
|
async def async_get_api(hass):
|
||||||
|
"""Get the pyipma api object."""
|
||||||
|
websession = async_get_clientsession(hass)
|
||||||
|
return IPMA_API(websession)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
"""Set up IPMA station as config entry."""
|
"""Set up IPMA station as config entry."""
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
|
||||||
|
latitude = config_entry.data[CONF_LATITUDE]
|
||||||
|
longitude = config_entry.data[CONF_LONGITUDE]
|
||||||
|
|
||||||
|
api = await async_get_api(hass)
|
||||||
|
try:
|
||||||
|
async with async_timeout.timeout(30):
|
||||||
|
location = await Location.get(api, float(latitude), float(longitude))
|
||||||
|
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Initializing for coordinates %s, %s -> station %s (%d, %d)",
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
location.station,
|
||||||
|
location.id_station,
|
||||||
|
location.global_id_local,
|
||||||
|
)
|
||||||
|
except IPMAException as err:
|
||||||
|
raise ConfigEntryNotReady(
|
||||||
|
f"Could not get location for ({latitude},{longitude})"
|
||||||
|
) from err
|
||||||
|
|
||||||
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
hass.data[DOMAIN][config_entry.entry_id] = {DATA_API: api, DATA_LOCATION: location}
|
||||||
|
|
||||||
|
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,6 @@ DOMAIN = "ipma"
|
||||||
HOME_LOCATION_NAME = "Home"
|
HOME_LOCATION_NAME = "Home"
|
||||||
|
|
||||||
ENTITY_ID_SENSOR_FORMAT_HOME = f"{WEATHER_DOMAIN}.ipma_{HOME_LOCATION_NAME}"
|
ENTITY_ID_SENSOR_FORMAT_HOME = f"{WEATHER_DOMAIN}.ipma_{HOME_LOCATION_NAME}"
|
||||||
|
|
||||||
|
DATA_LOCATION = "location"
|
||||||
|
DATA_API = "api"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "Instituto Portugu\u00eas do Mar e Atmosfera (IPMA)",
|
"name": "Instituto Portugu\u00eas do Mar e Atmosfera (IPMA)",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/ipma",
|
"documentation": "https://www.home-assistant.io/integrations/ipma",
|
||||||
"requirements": ["pyipma==3.0.2"],
|
"requirements": ["pyipma==3.0.4"],
|
||||||
"codeowners": ["@dgomes", "@abmantis"],
|
"codeowners": ["@dgomes", "@abmantis"],
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["geopy", "pyipma"]
|
"loggers": ["geopy", "pyipma"]
|
||||||
|
|
|
@ -48,11 +48,12 @@ from homeassistant.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.sun import is_up
|
from homeassistant.helpers.sun import is_up
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import Throttle
|
||||||
|
|
||||||
|
from .const import DATA_API, DATA_LOCATION, DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ATTRIBUTION = "Instituto Português do Mar e Atmosfera"
|
ATTRIBUTION = "Instituto Português do Mar e Atmosfera"
|
||||||
|
@ -95,13 +96,10 @@ async def async_setup_entry(
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add a weather entity from a config_entry."""
|
"""Add a weather entity from a config_entry."""
|
||||||
latitude = config_entry.data[CONF_LATITUDE]
|
api = hass.data[DOMAIN][config_entry.entry_id][DATA_API]
|
||||||
longitude = config_entry.data[CONF_LONGITUDE]
|
location = hass.data[DOMAIN][config_entry.entry_id][DATA_LOCATION]
|
||||||
mode = config_entry.data[CONF_MODE]
|
mode = config_entry.data[CONF_MODE]
|
||||||
|
|
||||||
api = await async_get_api(hass)
|
|
||||||
location = await async_get_location(hass, api, latitude, longitude)
|
|
||||||
|
|
||||||
# Migrate old unique_id
|
# Migrate old unique_id
|
||||||
@callback
|
@callback
|
||||||
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
|
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
|
||||||
|
@ -127,29 +125,6 @@ async def async_setup_entry(
|
||||||
async_add_entities([IPMAWeather(location, api, config_entry.data)], True)
|
async_add_entities([IPMAWeather(location, api, config_entry.data)], True)
|
||||||
|
|
||||||
|
|
||||||
async def async_get_api(hass):
|
|
||||||
"""Get the pyipma api object."""
|
|
||||||
websession = async_get_clientsession(hass)
|
|
||||||
return IPMA_API(websession)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_get_location(hass, api, latitude, longitude):
|
|
||||||
"""Retrieve pyipma location, location name to be used as the entity name."""
|
|
||||||
async with async_timeout.timeout(30):
|
|
||||||
location = await Location.get(api, float(latitude), float(longitude))
|
|
||||||
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Initializing for coordinates %s, %s -> station %s (%d, %d)",
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
location.station,
|
|
||||||
location.id_station,
|
|
||||||
location.global_id_local,
|
|
||||||
)
|
|
||||||
|
|
||||||
return location
|
|
||||||
|
|
||||||
|
|
||||||
class IPMAWeather(WeatherEntity):
|
class IPMAWeather(WeatherEntity):
|
||||||
"""Representation of a weather condition."""
|
"""Representation of a weather condition."""
|
||||||
|
|
||||||
|
|
|
@ -1614,7 +1614,7 @@ pyinsteon==1.2.0
|
||||||
pyintesishome==1.8.0
|
pyintesishome==1.8.0
|
||||||
|
|
||||||
# homeassistant.components.ipma
|
# homeassistant.components.ipma
|
||||||
pyipma==3.0.2
|
pyipma==3.0.4
|
||||||
|
|
||||||
# homeassistant.components.ipp
|
# homeassistant.components.ipp
|
||||||
pyipp==0.11.0
|
pyipp==0.11.0
|
||||||
|
|
|
@ -1127,7 +1127,7 @@ pyicloud==1.0.0
|
||||||
pyinsteon==1.2.0
|
pyinsteon==1.2.0
|
||||||
|
|
||||||
# homeassistant.components.ipma
|
# homeassistant.components.ipma
|
||||||
pyipma==3.0.2
|
pyipma==3.0.4
|
||||||
|
|
||||||
# homeassistant.components.ipp
|
# homeassistant.components.ipp
|
||||||
pyipp==0.11.0
|
pyipp==0.11.0
|
||||||
|
|
|
@ -168,7 +168,7 @@ async def test_config_entry_migration(hass):
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ipma.weather.async_get_location",
|
"pyipma.location.Location.get",
|
||||||
return_value=MockLocation(),
|
return_value=MockLocation(),
|
||||||
):
|
):
|
||||||
assert await async_setup_component(hass, DOMAIN, {})
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
|
|
|
@ -19,7 +19,6 @@ from homeassistant.components.weather import (
|
||||||
ATTR_WEATHER_TEMPERATURE,
|
ATTR_WEATHER_TEMPERATURE,
|
||||||
ATTR_WEATHER_WIND_BEARING,
|
ATTR_WEATHER_WIND_BEARING,
|
||||||
ATTR_WEATHER_WIND_SPEED,
|
ATTR_WEATHER_WIND_SPEED,
|
||||||
DOMAIN as WEATHER_DOMAIN,
|
|
||||||
)
|
)
|
||||||
from homeassistant.const import STATE_UNKNOWN
|
from homeassistant.const import STATE_UNKNOWN
|
||||||
|
|
||||||
|
@ -181,7 +180,8 @@ async def test_setup_config_flow(hass):
|
||||||
return_value=MockLocation(),
|
return_value=MockLocation(),
|
||||||
):
|
):
|
||||||
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG)
|
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG)
|
||||||
await hass.config_entries.async_forward_entry_setup(entry, WEATHER_DOMAIN)
|
entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("weather.hometown")
|
state = hass.states.get("weather.hometown")
|
||||||
|
@ -203,7 +203,8 @@ async def test_daily_forecast(hass):
|
||||||
return_value=MockLocation(),
|
return_value=MockLocation(),
|
||||||
):
|
):
|
||||||
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG)
|
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG)
|
||||||
await hass.config_entries.async_forward_entry_setup(entry, WEATHER_DOMAIN)
|
entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("weather.hometown")
|
state = hass.states.get("weather.hometown")
|
||||||
|
@ -227,7 +228,8 @@ async def test_hourly_forecast(hass):
|
||||||
return_value=MockLocation(),
|
return_value=MockLocation(),
|
||||||
):
|
):
|
||||||
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG_HOURLY)
|
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG_HOURLY)
|
||||||
await hass.config_entries.async_forward_entry_setup(entry, WEATHER_DOMAIN)
|
entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("weather.hometown")
|
state = hass.states.get("weather.hometown")
|
||||||
|
@ -248,7 +250,8 @@ async def test_failed_get_observation_forecast(hass):
|
||||||
return_value=MockBadLocation(),
|
return_value=MockBadLocation(),
|
||||||
):
|
):
|
||||||
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG)
|
entry = MockConfigEntry(domain="ipma", data=TEST_CONFIG)
|
||||||
await hass.config_entries.async_forward_entry_setup(entry, WEATHER_DOMAIN)
|
entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("weather.hometown")
|
state = hass.states.get("weather.hometown")
|
||||||
|
|
Loading…
Reference in New Issue