Support Wolflink reconnection after unexpected failure (#47011)

* Support reconnection after unexpected fails

* Update session at every call. Support Offline devices

* Remove unnecessary else branch

* Clean typing

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Adam Król 2021-06-17 05:24:17 +02:00 committed by GitHub
parent 33e08f38da
commit 986c4a8f29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 16 deletions

View File

@ -4,7 +4,7 @@ import logging
from httpx import ConnectError, ConnectTimeout from httpx import ConnectError, ConnectTimeout
from wolf_smartset.token_auth import InvalidAuth from wolf_smartset.token_auth import InvalidAuth
from wolf_smartset.wolf_client import FetchFailed, WolfClient from wolf_smartset.wolf_client import FetchFailed, ParameterReadError, WolfClient
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
@ -33,6 +33,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
device_name = entry.data[DEVICE_NAME] device_name = entry.data[DEVICE_NAME]
device_id = entry.data[DEVICE_ID] device_id = entry.data[DEVICE_ID]
gateway_id = entry.data[DEVICE_GATEWAY] gateway_id = entry.data[DEVICE_GATEWAY]
refetch_parameters = False
_LOGGER.debug( _LOGGER.debug(
"Setting up wolflink integration for device: %s (ID: %s, gateway: %s)", "Setting up wolflink integration for device: %s (ID: %s, gateway: %s)",
device_name, device_name,
@ -42,17 +43,37 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
wolf_client = WolfClient(username, password) wolf_client = WolfClient(username, password)
try: parameters = await fetch_parameters_init(wolf_client, gateway_id, device_id)
parameters = await fetch_parameters(wolf_client, gateway_id, device_id)
except InvalidAuth:
_LOGGER.debug("Authentication failed")
return False
async def async_update_data(): async def async_update_data():
"""Update all stored entities for Wolf SmartSet.""" """Update all stored entities for Wolf SmartSet."""
try: try:
values = await wolf_client.fetch_value(gateway_id, device_id, parameters) nonlocal refetch_parameters
return {v.value_id: v.value for v in values} nonlocal parameters
await wolf_client.update_session()
if not wolf_client.fetch_system_state_list(device_id, gateway_id):
refetch_parameters = True
raise UpdateFailed(
"Could not fetch values from server because device is Offline."
)
if refetch_parameters:
parameters = await fetch_parameters(wolf_client, gateway_id, device_id)
hass.data[DOMAIN][entry.entry_id][PARAMETERS] = parameters
refetch_parameters = False
values = {
v.value_id: v.value
for v in await wolf_client.fetch_value(
gateway_id, device_id, parameters
)
}
return {
parameter.parameter_id: (
parameter.value_id,
values[parameter.value_id],
)
for parameter in parameters
if parameter.value_id in values
}
except ConnectError as exception: except ConnectError as exception:
raise UpdateFailed( raise UpdateFailed(
f"Error communicating with API: {exception}" f"Error communicating with API: {exception}"
@ -61,13 +82,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
raise UpdateFailed( raise UpdateFailed(
f"Could not fetch values from server due to: {exception}" f"Could not fetch values from server due to: {exception}"
) from exception ) from exception
except ParameterReadError as exception:
refetch_parameters = True
raise UpdateFailed(
"Could not fetch values for parameter. Refreshing value IDs."
) from exception
except InvalidAuth as exception: except InvalidAuth as exception:
raise UpdateFailed("Invalid authentication during update.") from exception raise UpdateFailed("Invalid authentication during update.") from exception
coordinator = DataUpdateCoordinator( coordinator = DataUpdateCoordinator(
hass, hass,
_LOGGER, _LOGGER,
name="wolflink", name=DOMAIN,
update_method=async_update_data, update_method=async_update_data,
update_interval=timedelta(minutes=1), update_interval=timedelta(minutes=1),
) )
@ -100,9 +126,14 @@ async def fetch_parameters(client: WolfClient, gateway_id: int, device_id: int):
By default Reglertyp entity is removed because API will not provide value for this parameter. By default Reglertyp entity is removed because API will not provide value for this parameter.
""" """
try:
fetched_parameters = await client.fetch_parameters(gateway_id, device_id) fetched_parameters = await client.fetch_parameters(gateway_id, device_id)
return [param for param in fetched_parameters if param.name != "Reglertyp"] return [param for param in fetched_parameters if param.name != "Reglertyp"]
async def fetch_parameters_init(client: WolfClient, gateway_id: int, device_id: int):
"""Fetch all available parameters with usage of WolfClient but handles all exceptions and results in ConfigEntryNotReady."""
try:
return await fetch_parameters(client, gateway_id, device_id)
except (ConnectError, ConnectTimeout, FetchFailed) as exception: except (ConnectError, ConnectTimeout, FetchFailed) as exception:
raise ConfigEntryNotReady( raise ConfigEntryNotReady(
f"Error communicating with API: {exception}" f"Error communicating with API: {exception}"

View File

@ -3,7 +3,7 @@
"name": "Wolf SmartSet Service", "name": "Wolf SmartSet Service",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/wolflink", "documentation": "https://www.home-assistant.io/integrations/wolflink",
"requirements": ["wolf_smartset==0.1.8"], "requirements": ["wolf_smartset==0.1.11"],
"codeowners": ["@adamkrol93"], "codeowners": ["@adamkrol93"],
"iot_class": "cloud_polling" "iot_class": "cloud_polling"
} }

View File

@ -65,8 +65,10 @@ class WolfLinkSensor(CoordinatorEntity, SensorEntity):
@property @property
def state(self): def state(self):
"""Return the state. Wolf Client is returning only changed values so we need to store old value here.""" """Return the state. Wolf Client is returning only changed values so we need to store old value here."""
if self.wolf_object.value_id in self.coordinator.data: if self.wolf_object.parameter_id in self.coordinator.data:
self._state = self.coordinator.data[self.wolf_object.value_id] new_state = self.coordinator.data[self.wolf_object.parameter_id]
self.wolf_object.value_id = new_state[0]
self._state = new_state[1]
return self._state return self._state
@property @property

View File

@ -2368,7 +2368,7 @@ withings-api==2.3.2
wled==0.6.0 wled==0.6.0
# homeassistant.components.wolflink # homeassistant.components.wolflink
wolf_smartset==0.1.8 wolf_smartset==0.1.11
# homeassistant.components.xbee # homeassistant.components.xbee
xbee-helper==0.0.7 xbee-helper==0.0.7

View File

@ -1286,7 +1286,7 @@ withings-api==2.3.2
wled==0.6.0 wled==0.6.0
# homeassistant.components.wolflink # homeassistant.components.wolflink
wolf_smartset==0.1.8 wolf_smartset==0.1.11
# homeassistant.components.xbox # homeassistant.components.xbox
xbox-webapi==2.0.11 xbox-webapi==2.0.11