Enable Ruff TRY300 (#114437)
* Enable Ruff TRY300 * Update validation.py * Address review comments
This commit is contained in:
parent
9a79320861
commit
6587ee20db
97 changed files with 259 additions and 243 deletions
|
@ -60,10 +60,6 @@ class AmberElectricConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sites: list[Site] = filter_sites(api.get_sites())
|
sites: list[Site] = filter_sites(api.get_sites())
|
||||||
if len(sites) == 0:
|
|
||||||
self._errors[CONF_API_TOKEN] = "no_site"
|
|
||||||
return None
|
|
||||||
return sites
|
|
||||||
except amberelectric.ApiException as api_exception:
|
except amberelectric.ApiException as api_exception:
|
||||||
if api_exception.status == 403:
|
if api_exception.status == 403:
|
||||||
self._errors[CONF_API_TOKEN] = "invalid_api_token"
|
self._errors[CONF_API_TOKEN] = "invalid_api_token"
|
||||||
|
@ -71,6 +67,11 @@ class AmberElectricConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
self._errors[CONF_API_TOKEN] = "unknown_error"
|
self._errors[CONF_API_TOKEN] = "unknown_error"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if len(sites) == 0:
|
||||||
|
self._errors[CONF_API_TOKEN] = "no_site"
|
||||||
|
return None
|
||||||
|
return sites
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, str] | None = None
|
self, user_input: dict[str, str] | None = None
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
|
|
|
@ -76,9 +76,9 @@ async def device_scan(
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
ip_address(identifier)
|
ip_address(identifier)
|
||||||
return [identifier]
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
return [identifier]
|
||||||
|
|
||||||
# If we have an address, only probe that address to avoid
|
# If we have an address, only probe that address to avoid
|
||||||
# broadcast traffic on the network
|
# broadcast traffic on the network
|
||||||
|
|
|
@ -127,9 +127,9 @@ def verify_client_id(client_id: str) -> bool:
|
||||||
"""Verify that the client id is valid."""
|
"""Verify that the client id is valid."""
|
||||||
try:
|
try:
|
||||||
_parse_client_id(client_id)
|
_parse_client_id(client_id)
|
||||||
return True
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _parse_url(url: str) -> ParseResult:
|
def _parse_url(url: str) -> ParseResult:
|
||||||
|
|
|
@ -250,13 +250,12 @@ class AwairFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||||
try:
|
try:
|
||||||
user = await awair.user()
|
user = await awair.user()
|
||||||
devices = await user.devices()
|
devices = await user.devices()
|
||||||
if not devices:
|
|
||||||
return (None, "no_devices_found")
|
|
||||||
|
|
||||||
return (user, None)
|
|
||||||
|
|
||||||
except AuthError:
|
except AuthError:
|
||||||
return (None, "invalid_access_token")
|
return (None, "invalid_access_token")
|
||||||
except AwairError as err:
|
except AwairError as err:
|
||||||
LOGGER.error("Unexpected API error: %s", err)
|
LOGGER.error("Unexpected API error: %s", err)
|
||||||
return (None, "unknown")
|
return (None, "unknown")
|
||||||
|
|
||||||
|
if not devices:
|
||||||
|
return (None, "no_devices_found")
|
||||||
|
return (user, None)
|
||||||
|
|
|
@ -111,7 +111,7 @@ class AwairLocalDataUpdateCoordinator(AwairDataUpdateCoordinator):
|
||||||
devices = await self._awair.devices()
|
devices = await self._awair.devices()
|
||||||
self._device = devices[0]
|
self._device = devices[0]
|
||||||
result = await self._fetch_air_data(self._device)
|
result = await self._fetch_air_data(self._device)
|
||||||
return {result.device.uuid: result}
|
|
||||||
except AwairError as err:
|
except AwairError as err:
|
||||||
LOGGER.error("Unexpected API error: %s", err)
|
LOGGER.error("Unexpected API error: %s", err)
|
||||||
raise UpdateFailed(err) from err
|
raise UpdateFailed(err) from err
|
||||||
|
return {result.device.uuid: result}
|
||||||
|
|
|
@ -819,22 +819,23 @@ class BrSensor(SensorEntity):
|
||||||
self._attr_native_value = data.get(FORECAST)[fcday].get(
|
self._attr_native_value = data.get(FORECAST)[fcday].get(
|
||||||
sensor_type[:-3]
|
sensor_type[:-3]
|
||||||
)
|
)
|
||||||
if self.state is not None:
|
|
||||||
self._attr_native_value = round(self.state * 3.6, 1)
|
|
||||||
return True
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
_LOGGER.warning("No forecast for fcday=%s", fcday)
|
_LOGGER.warning("No forecast for fcday=%s", fcday)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if self.state is not None:
|
||||||
|
self._attr_native_value = round(self.state * 3.6, 1)
|
||||||
|
return True
|
||||||
|
|
||||||
# update all other sensors
|
# update all other sensors
|
||||||
try:
|
try:
|
||||||
self._attr_native_value = data.get(FORECAST)[fcday].get(
|
self._attr_native_value = data.get(FORECAST)[fcday].get(
|
||||||
sensor_type[:-3]
|
sensor_type[:-3]
|
||||||
)
|
)
|
||||||
return True
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
_LOGGER.warning("No forecast for fcday=%s", fcday)
|
_LOGGER.warning("No forecast for fcday=%s", fcday)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
if sensor_type == SYMBOL or sensor_type.startswith(CONDITION):
|
if sensor_type == SYMBOL or sensor_type.startswith(CONDITION):
|
||||||
# update weather symbol & status text
|
# update weather symbol & status text
|
||||||
|
|
|
@ -43,7 +43,6 @@ class CertexpiryConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
user_input[CONF_HOST],
|
user_input[CONF_HOST],
|
||||||
user_input.get(CONF_PORT, DEFAULT_PORT),
|
user_input.get(CONF_PORT, DEFAULT_PORT),
|
||||||
)
|
)
|
||||||
return True
|
|
||||||
except ResolveFailed:
|
except ResolveFailed:
|
||||||
self._errors[CONF_HOST] = "resolve_failed"
|
self._errors[CONF_HOST] = "resolve_failed"
|
||||||
except ConnectionTimeout:
|
except ConnectionTimeout:
|
||||||
|
@ -52,6 +51,8 @@ class CertexpiryConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
self._errors[CONF_HOST] = "connection_refused"
|
self._errors[CONF_HOST] = "connection_refused"
|
||||||
except ValidationFailure:
|
except ValidationFailure:
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
|
|
|
@ -228,6 +228,9 @@ class CityBikesNetworks:
|
||||||
self.hass, NETWORKS_URI, NETWORKS_RESPONSE_SCHEMA
|
self.hass, NETWORKS_URI, NETWORKS_RESPONSE_SCHEMA
|
||||||
)
|
)
|
||||||
self.networks = networks[ATTR_NETWORKS_LIST]
|
self.networks = networks[ATTR_NETWORKS_LIST]
|
||||||
|
except CityBikesRequestError as err:
|
||||||
|
raise PlatformNotReady from err
|
||||||
|
else:
|
||||||
result = None
|
result = None
|
||||||
minimum_dist = None
|
minimum_dist = None
|
||||||
for network in self.networks:
|
for network in self.networks:
|
||||||
|
@ -241,8 +244,6 @@ class CityBikesNetworks:
|
||||||
result = network[ATTR_ID]
|
result = network[ATTR_ID]
|
||||||
|
|
||||||
return result
|
return result
|
||||||
except CityBikesRequestError as err:
|
|
||||||
raise PlatformNotReady from err
|
|
||||||
finally:
|
finally:
|
||||||
self.networks_loading.release()
|
self.networks_loading.release()
|
||||||
|
|
||||||
|
|
|
@ -509,16 +509,13 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
|
||||||
try:
|
try:
|
||||||
async with asyncio.timeout(10):
|
async with asyncio.timeout(10):
|
||||||
await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)
|
await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
_LOGGER.warning("Timeout trying to sync entities to Alexa")
|
_LOGGER.warning("Timeout trying to sync entities to Alexa")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except aiohttp.ClientError as err:
|
except aiohttp.ClientError as err:
|
||||||
_LOGGER.warning("Error trying to sync entities to Alexa: %s", err)
|
_LOGGER.warning("Error trying to sync entities to Alexa: %s", err)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def _handle_entity_registry_updated(self, event: Event) -> None:
|
async def _handle_entity_registry_updated(self, event: Event) -> None:
|
||||||
"""Handle when entity registry updated."""
|
"""Handle when entity registry updated."""
|
||||||
|
|
|
@ -135,12 +135,12 @@ def _handle_cloud_errors(
|
||||||
"""Handle exceptions that raise from the wrapped request handler."""
|
"""Handle exceptions that raise from the wrapped request handler."""
|
||||||
try:
|
try:
|
||||||
result = await handler(view, request, *args, **kwargs)
|
result = await handler(view, request, *args, **kwargs)
|
||||||
return result
|
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
status, msg = _process_cloud_exception(err, request.path)
|
status, msg = _process_cloud_exception(err, request.path)
|
||||||
return view.json_message(
|
return view.json_message(
|
||||||
msg, status_code=status, message_code=err.__class__.__name__.lower()
|
msg, status_code=status, message_code=err.__class__.__name__.lower()
|
||||||
)
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
return error_handler
|
return error_handler
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@ async def async_call_shell_with_timeout(
|
||||||
)
|
)
|
||||||
async with asyncio.timeout(timeout):
|
async with asyncio.timeout(timeout):
|
||||||
await proc.communicate()
|
await proc.communicate()
|
||||||
|
except TimeoutError:
|
||||||
|
_LOGGER.error("Timeout for command: %s", command)
|
||||||
|
return -1
|
||||||
|
|
||||||
return_code = proc.returncode
|
return_code = proc.returncode
|
||||||
if return_code == _EXEC_FAILED_CODE:
|
if return_code == _EXEC_FAILED_CODE:
|
||||||
_LOGGER.error("Error trying to exec command: %s", command)
|
_LOGGER.error("Error trying to exec command: %s", command)
|
||||||
|
@ -35,9 +39,6 @@ async def async_call_shell_with_timeout(
|
||||||
command,
|
command,
|
||||||
)
|
)
|
||||||
return return_code or 0
|
return return_code or 0
|
||||||
except TimeoutError:
|
|
||||||
_LOGGER.error("Timeout for command: %s", command)
|
|
||||||
return -1
|
|
||||||
|
|
||||||
|
|
||||||
async def async_check_output_or_log(command: str, timeout: int) -> str | None:
|
async def async_check_output_or_log(command: str, timeout: int) -> str | None:
|
||||||
|
|
|
@ -68,9 +68,9 @@ class Control4Validator:
|
||||||
self.director_bearer_token = (
|
self.director_bearer_token = (
|
||||||
await account.getDirectorBearerToken(self.controller_unique_id)
|
await account.getDirectorBearerToken(self.controller_unique_id)
|
||||||
)["token"]
|
)["token"]
|
||||||
return True
|
|
||||||
except (Unauthorized, NotFound):
|
except (Unauthorized, NotFound):
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def connect_to_director(self) -> bool:
|
async def connect_to_director(self) -> bool:
|
||||||
"""Test if we can connect to the local Control4 Director."""
|
"""Test if we can connect to the local Control4 Director."""
|
||||||
|
@ -82,10 +82,10 @@ class Control4Validator:
|
||||||
self.host, self.director_bearer_token, director_session
|
self.host, self.director_bearer_token, director_session
|
||||||
)
|
)
|
||||||
await director.getAllItemInfo()
|
await director.getAllItemInfo()
|
||||||
return True
|
|
||||||
except (Unauthorized, ClientError, TimeoutError):
|
except (Unauthorized, ClientError, TimeoutError):
|
||||||
_LOGGER.error("Failed to connect to the Control4 controller")
|
_LOGGER.error("Failed to connect to the Control4 controller")
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Control4ConfigFlow(ConfigFlow, domain=DOMAIN):
|
class Control4ConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
|
|
|
@ -26,7 +26,6 @@ async def get_deconz_api(
|
||||||
try:
|
try:
|
||||||
async with asyncio.timeout(10):
|
async with asyncio.timeout(10):
|
||||||
await api.refresh_state()
|
await api.refresh_state()
|
||||||
return api
|
|
||||||
|
|
||||||
except errors.Unauthorized as err:
|
except errors.Unauthorized as err:
|
||||||
LOGGER.warning("Invalid key for deCONZ at %s", config.host)
|
LOGGER.warning("Invalid key for deCONZ at %s", config.host)
|
||||||
|
@ -35,3 +34,4 @@ async def get_deconz_api(
|
||||||
except (TimeoutError, errors.RequestError, errors.ResponseError) as err:
|
except (TimeoutError, errors.RequestError, errors.ResponseError) as err:
|
||||||
LOGGER.error("Error connecting to deCONZ gateway at %s", config.host)
|
LOGGER.error("Error connecting to deCONZ gateway at %s", config.host)
|
||||||
raise CannotConnect from err
|
raise CannotConnect from err
|
||||||
|
return api
|
||||||
|
|
|
@ -139,10 +139,10 @@ class Dominos:
|
||||||
"""Update the shared closest store (if open)."""
|
"""Update the shared closest store (if open)."""
|
||||||
try:
|
try:
|
||||||
self.closest_store = self.address.closest_store()
|
self.closest_store = self.address.closest_store()
|
||||||
return True
|
|
||||||
except StoreException:
|
except StoreException:
|
||||||
self.closest_store = None
|
self.closest_store = None
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def get_menu(self):
|
def get_menu(self):
|
||||||
"""Return the products from the closest stores menu."""
|
"""Return the products from the closest stores menu."""
|
||||||
|
|
|
@ -107,8 +107,6 @@ class DoorBirdCamera(DoorBirdEntity, Camera):
|
||||||
response = await websession.get(self._url)
|
response = await websession.get(self._url)
|
||||||
|
|
||||||
self._last_image = await response.read()
|
self._last_image = await response.read()
|
||||||
self._last_update = now
|
|
||||||
return self._last_image
|
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
_LOGGER.error("DoorBird %s: Camera image timed out", self.name)
|
_LOGGER.error("DoorBird %s: Camera image timed out", self.name)
|
||||||
return self._last_image
|
return self._last_image
|
||||||
|
@ -118,6 +116,9 @@ class DoorBirdCamera(DoorBirdEntity, Camera):
|
||||||
)
|
)
|
||||||
return self._last_image
|
return self._last_image
|
||||||
|
|
||||||
|
self._last_update = now
|
||||||
|
return self._last_image
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Subscribe to events."""
|
"""Subscribe to events."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
|
@ -74,10 +74,11 @@ class DovadoData:
|
||||||
if not self.state:
|
if not self.state:
|
||||||
return False
|
return False
|
||||||
self.state.update(connected=self.state.get("modem status") == "CONNECTED")
|
self.state.update(connected=self.state.get("modem status") == "CONNECTED")
|
||||||
_LOGGER.debug("Received: %s", self.state)
|
|
||||||
return True
|
|
||||||
except OSError as error:
|
except OSError as error:
|
||||||
_LOGGER.warning("Could not contact the router: %s", error)
|
_LOGGER.warning("Could not contact the router: %s", error)
|
||||||
|
return None
|
||||||
|
_LOGGER.debug("Received: %s", self.state)
|
||||||
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def client(self):
|
def client(self):
|
||||||
|
|
|
@ -67,8 +67,9 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ebusdpy.init(server_address)
|
ebusdpy.init(server_address)
|
||||||
|
except (TimeoutError, OSError):
|
||||||
|
return False
|
||||||
hass.data[DOMAIN] = EbusdData(server_address, circuit)
|
hass.data[DOMAIN] = EbusdData(server_address, circuit)
|
||||||
|
|
||||||
sensor_config = {
|
sensor_config = {
|
||||||
CONF_MONITORED_CONDITIONS: monitored_conditions,
|
CONF_MONITORED_CONDITIONS: monitored_conditions,
|
||||||
"client_name": name,
|
"client_name": name,
|
||||||
|
@ -80,8 +81,6 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
|
||||||
_LOGGER.debug("Ebusd integration setup completed")
|
_LOGGER.debug("Ebusd integration setup completed")
|
||||||
return True
|
return True
|
||||||
except (TimeoutError, OSError):
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class EbusdData:
|
class EbusdData:
|
||||||
|
|
|
@ -32,7 +32,8 @@ class EcoforestCoordinator(DataUpdateCoordinator[Device]):
|
||||||
"""Fetch all device and sensor data from api."""
|
"""Fetch all device and sensor data from api."""
|
||||||
try:
|
try:
|
||||||
data = await self.api.get()
|
data = await self.api.get()
|
||||||
_LOGGER.debug("Ecoforest data: %s", data)
|
|
||||||
return data
|
|
||||||
except EcoforestError as err:
|
except EcoforestError as err:
|
||||||
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
||||||
|
|
||||||
|
_LOGGER.debug("Ecoforest data: %s", data)
|
||||||
|
return data
|
||||||
|
|
|
@ -82,7 +82,7 @@ def validate_path(path: str):
|
||||||
# Creating the serial communicator will raise an exception
|
# Creating the serial communicator will raise an exception
|
||||||
# if it cannot connect
|
# if it cannot connect
|
||||||
SerialCommunicator(port=path)
|
SerialCommunicator(port=path)
|
||||||
return True
|
|
||||||
except serial.SerialException as exception:
|
except serial.SerialException as exception:
|
||||||
_LOGGER.warning("Dongle path %s is invalid: %s", path, str(exception))
|
_LOGGER.warning("Dongle path %s is invalid: %s", path, str(exception))
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
|
@ -147,8 +147,6 @@ class EnphaseUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||||
self._async_mark_setup_complete()
|
self._async_mark_setup_complete()
|
||||||
# dump all received data in debug mode to assist troubleshooting
|
# dump all received data in debug mode to assist troubleshooting
|
||||||
envoy_data = await envoy.update()
|
envoy_data = await envoy.update()
|
||||||
_LOGGER.debug("Envoy data: %s", envoy_data)
|
|
||||||
return envoy_data.raw
|
|
||||||
except INVALID_AUTH_ERRORS as err:
|
except INVALID_AUTH_ERRORS as err:
|
||||||
if self._setup_complete and tries == 0:
|
if self._setup_complete and tries == 0:
|
||||||
# token likely expired or firmware changed, try to re-authenticate
|
# token likely expired or firmware changed, try to re-authenticate
|
||||||
|
@ -157,5 +155,7 @@ class EnphaseUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||||
raise ConfigEntryAuthFailed from err
|
raise ConfigEntryAuthFailed from err
|
||||||
except EnvoyError as err:
|
except EnvoyError as err:
|
||||||
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
||||||
|
_LOGGER.debug("Envoy data: %s", envoy_data)
|
||||||
|
return envoy_data.raw
|
||||||
|
|
||||||
raise RuntimeError("Unreachable code in _async_update_data") # pragma: no cover
|
raise RuntimeError("Unreachable code in _async_update_data") # pragma: no cover
|
||||||
|
|
|
@ -43,7 +43,6 @@ def is_json(json_str: str) -> bool:
|
||||||
"""Validate if a String is a JSON value or not."""
|
"""Validate if a String is a JSON value or not."""
|
||||||
try:
|
try:
|
||||||
json.loads(json_str)
|
json.loads(json_str)
|
||||||
return True
|
|
||||||
except (ValueError, TypeError) as err:
|
except (ValueError, TypeError) as err:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Failed to parse JSON '%s', error '%s'",
|
"Failed to parse JSON '%s', error '%s'",
|
||||||
|
@ -51,6 +50,7 @@ def is_json(json_str: str) -> bool:
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def get_api(hass: HomeAssistant, host: str) -> Freepybox:
|
async def get_api(hass: HomeAssistant, host: str) -> Freepybox:
|
||||||
|
|
|
@ -789,24 +789,26 @@ class AvmWrapper(FritzBoxTools): # pylint: disable=hass-enforce-coordinator-mod
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return result
|
|
||||||
except FritzSecurityError:
|
except FritzSecurityError:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Authorization Error: Please check the provided credentials and"
|
"Authorization Error: Please check the provided credentials and"
|
||||||
" verify that you can log into the web interface"
|
" verify that you can log into the web interface"
|
||||||
)
|
)
|
||||||
|
return {}
|
||||||
except FRITZ_EXCEPTIONS:
|
except FRITZ_EXCEPTIONS:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Service/Action Error: cannot execute service %s with action %s",
|
"Service/Action Error: cannot execute service %s with action %s",
|
||||||
service_name,
|
service_name,
|
||||||
action_name,
|
action_name,
|
||||||
)
|
)
|
||||||
|
return {}
|
||||||
except FritzConnectionException:
|
except FritzConnectionException:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Connection Error: Please check the device is properly configured"
|
"Connection Error: Please check the device is properly configured"
|
||||||
" for remote login"
|
" for remote login"
|
||||||
)
|
)
|
||||||
return {}
|
return {}
|
||||||
|
return result
|
||||||
|
|
||||||
async def async_get_upnp_configuration(self) -> dict[str, Any]:
|
async def async_get_upnp_configuration(self) -> dict[str, Any]:
|
||||||
"""Call X_AVM-DE_UPnP service."""
|
"""Call X_AVM-DE_UPnP service."""
|
||||||
|
|
|
@ -82,13 +82,13 @@ class FritzboxConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
fritzbox.login()
|
fritzbox.login()
|
||||||
fritzbox.get_device_elements()
|
fritzbox.get_device_elements()
|
||||||
fritzbox.logout()
|
fritzbox.logout()
|
||||||
return RESULT_SUCCESS
|
|
||||||
except LoginError:
|
except LoginError:
|
||||||
return RESULT_INVALID_AUTH
|
return RESULT_INVALID_AUTH
|
||||||
except HTTPError:
|
except HTTPError:
|
||||||
return RESULT_NOT_SUPPORTED
|
return RESULT_NOT_SUPPORTED
|
||||||
except OSError:
|
except OSError:
|
||||||
return RESULT_NO_DEVICES_FOUND
|
return RESULT_NO_DEVICES_FOUND
|
||||||
|
return RESULT_SUCCESS
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
|
|
@ -109,9 +109,6 @@ class FritzBoxCallMonitorConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
address=self._host, user=self._username, password=self._password
|
address=self._host, user=self._username, password=self._password
|
||||||
)
|
)
|
||||||
info = fritz_connection.updatecheck
|
info = fritz_connection.updatecheck
|
||||||
self._serial_number = info[FRITZ_ATTR_SERIAL_NUMBER]
|
|
||||||
|
|
||||||
return ConnectResult.SUCCESS
|
|
||||||
except RequestsConnectionError:
|
except RequestsConnectionError:
|
||||||
return ConnectResult.NO_DEVIES_FOUND
|
return ConnectResult.NO_DEVIES_FOUND
|
||||||
except FritzSecurityError:
|
except FritzSecurityError:
|
||||||
|
@ -119,6 +116,9 @@ class FritzBoxCallMonitorConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
except FritzConnectionException:
|
except FritzConnectionException:
|
||||||
return ConnectResult.INVALID_AUTH
|
return ConnectResult.INVALID_AUTH
|
||||||
|
|
||||||
|
self._serial_number = info[FRITZ_ATTR_SERIAL_NUMBER]
|
||||||
|
return ConnectResult.SUCCESS
|
||||||
|
|
||||||
async def _get_name_of_phonebook(self, phonebook_id: int) -> str:
|
async def _get_name_of_phonebook(self, phonebook_id: int) -> str:
|
||||||
"""Return name of phonebook for given phonebook_id."""
|
"""Return name of phonebook for given phonebook_id."""
|
||||||
phonebook_info = await self.hass.async_add_executor_job(
|
phonebook_info = await self.hass.async_add_executor_job(
|
||||||
|
|
|
@ -483,28 +483,28 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator): # pylint: disable=has
|
||||||
"""Update single addon stats."""
|
"""Update single addon stats."""
|
||||||
try:
|
try:
|
||||||
stats = await self.hassio.get_addon_stats(slug)
|
stats = await self.hassio.get_addon_stats(slug)
|
||||||
return (slug, stats)
|
|
||||||
except HassioAPIError as err:
|
except HassioAPIError as err:
|
||||||
_LOGGER.warning("Could not fetch stats for %s: %s", slug, err)
|
_LOGGER.warning("Could not fetch stats for %s: %s", slug, err)
|
||||||
return (slug, None)
|
return (slug, None)
|
||||||
|
return (slug, stats)
|
||||||
|
|
||||||
async def _update_addon_changelog(self, slug: str) -> tuple[str, str | None]:
|
async def _update_addon_changelog(self, slug: str) -> tuple[str, str | None]:
|
||||||
"""Return the changelog for an add-on."""
|
"""Return the changelog for an add-on."""
|
||||||
try:
|
try:
|
||||||
changelog = await self.hassio.get_addon_changelog(slug)
|
changelog = await self.hassio.get_addon_changelog(slug)
|
||||||
return (slug, changelog)
|
|
||||||
except HassioAPIError as err:
|
except HassioAPIError as err:
|
||||||
_LOGGER.warning("Could not fetch changelog for %s: %s", slug, err)
|
_LOGGER.warning("Could not fetch changelog for %s: %s", slug, err)
|
||||||
return (slug, None)
|
return (slug, None)
|
||||||
|
return (slug, changelog)
|
||||||
|
|
||||||
async def _update_addon_info(self, slug: str) -> tuple[str, dict[str, Any] | None]:
|
async def _update_addon_info(self, slug: str) -> tuple[str, dict[str, Any] | None]:
|
||||||
"""Return the info for an add-on."""
|
"""Return the info for an add-on."""
|
||||||
try:
|
try:
|
||||||
info = await self.hassio.get_addon_info(slug)
|
info = await self.hassio.get_addon_info(slug)
|
||||||
return (slug, info)
|
|
||||||
except HassioAPIError as err:
|
except HassioAPIError as err:
|
||||||
_LOGGER.warning("Could not fetch info for %s: %s", slug, err)
|
_LOGGER.warning("Could not fetch info for %s: %s", slug, err)
|
||||||
return (slug, None)
|
return (slug, None)
|
||||||
|
return (slug, info)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_enable_container_updates(
|
def async_enable_container_updates(
|
||||||
|
|
|
@ -188,15 +188,13 @@ class HassIOView(HomeAssistantView):
|
||||||
async for data, _ in client.content.iter_chunks():
|
async for data, _ in client.content.iter_chunks():
|
||||||
await response.write(data)
|
await response.write(data)
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
except aiohttp.ClientError as err:
|
except aiohttp.ClientError as err:
|
||||||
_LOGGER.error("Client error on api %s request %s", path, err)
|
_LOGGER.error("Client error on api %s request %s", path, err)
|
||||||
|
raise HTTPBadGateway from err
|
||||||
except TimeoutError:
|
except TimeoutError as err:
|
||||||
_LOGGER.error("Client timeout error on API request %s", path)
|
_LOGGER.error("Client timeout error on API request %s", path)
|
||||||
|
raise HTTPBadGateway from err
|
||||||
raise HTTPBadGateway
|
return response
|
||||||
|
|
||||||
get = _handle
|
get = _handle
|
||||||
post = _handle
|
post = _handle
|
||||||
|
|
|
@ -478,7 +478,6 @@ class SourceManager:
|
||||||
if controller.is_signed_in:
|
if controller.is_signed_in:
|
||||||
favorites = await controller.get_favorites()
|
favorites = await controller.get_favorites()
|
||||||
inputs = await controller.get_input_sources()
|
inputs = await controller.get_input_sources()
|
||||||
return favorites, inputs
|
|
||||||
except HeosError as error:
|
except HeosError as error:
|
||||||
if retry_attempts < self.max_retry_attempts:
|
if retry_attempts < self.max_retry_attempts:
|
||||||
retry_attempts += 1
|
retry_attempts += 1
|
||||||
|
@ -488,7 +487,9 @@ class SourceManager:
|
||||||
await asyncio.sleep(self.retry_delay)
|
await asyncio.sleep(self.retry_delay)
|
||||||
else:
|
else:
|
||||||
_LOGGER.error("Unable to update sources: %s", error)
|
_LOGGER.error("Unable to update sources: %s", error)
|
||||||
return
|
return None
|
||||||
|
else:
|
||||||
|
return favorites, inputs
|
||||||
|
|
||||||
async def update_sources(event, data=None):
|
async def update_sources(event, data=None):
|
||||||
if event in (
|
if event in (
|
||||||
|
|
|
@ -95,10 +95,10 @@ class HitronCODADeviceScanner(DeviceScanner):
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
self._userid = res.cookies["userid"]
|
self._userid = res.cookies["userid"]
|
||||||
return True
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
_LOGGER.error("Failed to log in to router")
|
_LOGGER.error("Failed to log in to router")
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _update_info(self):
|
def _update_info(self):
|
||||||
"""Get ARP from router."""
|
"""Get ARP from router."""
|
||||||
|
|
|
@ -494,11 +494,12 @@ class Camera(HomeAccessory, PyhapCamera): # type: ignore[misc]
|
||||||
_LOGGER.info("[%s] %s stream", session_id, shutdown_method)
|
_LOGGER.info("[%s] %s stream", session_id, shutdown_method)
|
||||||
try:
|
try:
|
||||||
await getattr(stream, shutdown_method)()
|
await getattr(stream, shutdown_method)()
|
||||||
return
|
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"[%s] Failed to %s stream", session_id, shutdown_method
|
"[%s] Failed to %s stream", session_id, shutdown_method
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
async def reconfigure_stream(
|
async def reconfigure_stream(
|
||||||
self, session_info: dict[str, Any], stream_config: dict[str, Any]
|
self, session_info: dict[str, Any], stream_config: dict[str, Any]
|
||||||
|
|
|
@ -572,11 +572,12 @@ def _async_find_next_available_port(start_port: int, exclude_ports: set) -> int:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
test_socket.bind(("", port))
|
test_socket.bind(("", port))
|
||||||
return port
|
|
||||||
except OSError:
|
except OSError:
|
||||||
if port == MAX_PORT:
|
if port == MAX_PORT:
|
||||||
raise
|
raise
|
||||||
continue
|
continue
|
||||||
|
else:
|
||||||
|
return port
|
||||||
raise RuntimeError("unreachable")
|
raise RuntimeError("unreachable")
|
||||||
|
|
||||||
|
|
||||||
|
@ -584,10 +585,9 @@ def pid_is_alive(pid: int) -> bool:
|
||||||
"""Check to see if a process is alive."""
|
"""Check to see if a process is alive."""
|
||||||
try:
|
try:
|
||||||
os.kill(pid, 0)
|
os.kill(pid, 0)
|
||||||
return True
|
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def accessory_friendly_name(hass_name: str, accessory: Accessory) -> str:
|
def accessory_friendly_name(hass_name: str, accessory: Accessory) -> str:
|
||||||
|
|
|
@ -39,9 +39,9 @@ class HomematicipAuth:
|
||||||
self.auth = await self.get_auth(
|
self.auth = await self.get_auth(
|
||||||
self.hass, self.config.get(HMIPC_HAPID), self.config.get(HMIPC_PIN)
|
self.hass, self.config.get(HMIPC_HAPID), self.config.get(HMIPC_PIN)
|
||||||
)
|
)
|
||||||
return self.auth is not None
|
|
||||||
except HmipcConnectionError:
|
except HmipcConnectionError:
|
||||||
return False
|
return False
|
||||||
|
return self.auth is not None
|
||||||
|
|
||||||
async def async_checkbutton(self) -> bool:
|
async def async_checkbutton(self) -> bool:
|
||||||
"""Check blue butten has been pressed."""
|
"""Check blue butten has been pressed."""
|
||||||
|
@ -55,9 +55,9 @@ class HomematicipAuth:
|
||||||
try:
|
try:
|
||||||
authtoken = await self.auth.requestAuthToken()
|
authtoken = await self.auth.requestAuthToken()
|
||||||
await self.auth.confirmAuthToken(authtoken)
|
await self.auth.confirmAuthToken(authtoken)
|
||||||
return authtoken
|
|
||||||
except HmipConnectionError:
|
except HmipConnectionError:
|
||||||
return False
|
return False
|
||||||
|
return authtoken
|
||||||
|
|
||||||
async def get_auth(self, hass: HomeAssistant, hapid, pin):
|
async def get_auth(self, hass: HomeAssistant, hapid, pin):
|
||||||
"""Create a HomematicIP access point object."""
|
"""Create a HomematicIP access point object."""
|
||||||
|
|
|
@ -79,9 +79,9 @@ def format_last_reset_elapsed_seconds(value: str | None) -> datetime | None:
|
||||||
try:
|
try:
|
||||||
last_reset = datetime.now() - timedelta(seconds=int(value))
|
last_reset = datetime.now() - timedelta(seconds=int(value))
|
||||||
last_reset.replace(microsecond=0)
|
last_reset.replace(microsecond=0)
|
||||||
return last_reset
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
return last_reset
|
||||||
|
|
||||||
|
|
||||||
def signal_icon(limits: Sequence[int], value: StateType) -> str:
|
def signal_icon(limits: Sequence[int], value: StateType) -> str:
|
||||||
|
|
|
@ -199,7 +199,6 @@ class ImageEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
||||||
url, timeout=GET_IMAGE_TIMEOUT, follow_redirects=True
|
url, timeout=GET_IMAGE_TIMEOUT, follow_redirects=True
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response
|
|
||||||
except httpx.TimeoutException:
|
except httpx.TimeoutException:
|
||||||
_LOGGER.error("%s: Timeout getting image from %s", self.entity_id, url)
|
_LOGGER.error("%s: Timeout getting image from %s", self.entity_id, url)
|
||||||
return None
|
return None
|
||||||
|
@ -211,6 +210,7 @@ class ImageEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
return response
|
||||||
|
|
||||||
async def _async_load_image_from_url(self, url: str) -> Image | None:
|
async def _async_load_image_from_url(self, url: str) -> Image | None:
|
||||||
"""Load an image by url."""
|
"""Load an image by url."""
|
||||||
|
|
|
@ -398,8 +398,6 @@ class ImapPollingDataUpdateCoordinator(ImapDataUpdateCoordinator):
|
||||||
"""Update the number of unread emails."""
|
"""Update the number of unread emails."""
|
||||||
try:
|
try:
|
||||||
messages = await self._async_fetch_number_of_messages()
|
messages = await self._async_fetch_number_of_messages()
|
||||||
self.auth_errors = 0
|
|
||||||
return messages
|
|
||||||
except (
|
except (
|
||||||
AioImapException,
|
AioImapException,
|
||||||
UpdateFailed,
|
UpdateFailed,
|
||||||
|
@ -426,6 +424,9 @@ class ImapPollingDataUpdateCoordinator(ImapDataUpdateCoordinator):
|
||||||
self.async_set_update_error(ex)
|
self.async_set_update_error(ex)
|
||||||
raise ConfigEntryAuthFailed from ex
|
raise ConfigEntryAuthFailed from ex
|
||||||
|
|
||||||
|
self.auth_errors = 0
|
||||||
|
return messages
|
||||||
|
|
||||||
|
|
||||||
class ImapPushDataUpdateCoordinator(ImapDataUpdateCoordinator):
|
class ImapPushDataUpdateCoordinator(ImapDataUpdateCoordinator):
|
||||||
"""Class for imap client."""
|
"""Class for imap client."""
|
||||||
|
|
|
@ -72,12 +72,13 @@ async def _async_connect(**kwargs):
|
||||||
"""Connect to the Insteon modem."""
|
"""Connect to the Insteon modem."""
|
||||||
try:
|
try:
|
||||||
await async_connect(**kwargs)
|
await async_connect(**kwargs)
|
||||||
_LOGGER.info("Connected to Insteon modem")
|
|
||||||
return True
|
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
_LOGGER.error("Could not connect to Insteon modem")
|
_LOGGER.error("Could not connect to Insteon modem")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
_LOGGER.info("Connected to Insteon modem")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _remove_override(address, options):
|
def _remove_override(address, options):
|
||||||
"""Remove a device override from config."""
|
"""Remove a device override from config."""
|
||||||
|
|
|
@ -145,9 +145,9 @@ class _Right(_IntegrationMethod):
|
||||||
def _is_numeric_state(state: State) -> bool:
|
def _is_numeric_state(state: State) -> bool:
|
||||||
try:
|
try:
|
||||||
float(state.state)
|
float(state.state)
|
||||||
return True
|
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
_NAME_TO_INTEGRATION_METHOD: dict[str, type[_IntegrationMethod]] = {
|
_NAME_TO_INTEGRATION_METHOD: dict[str, type[_IntegrationMethod]] = {
|
||||||
|
|
|
@ -79,12 +79,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
def get_ip_mode(host):
|
def get_ip_mode(host):
|
||||||
"""Get the 'mode' used to retrieve the MAC address."""
|
"""Get the 'mode' used to retrieve the MAC address."""
|
||||||
try:
|
try:
|
||||||
if ipaddress.ip_address(host).version == 6:
|
ip_address = ipaddress.ip_address(host)
|
||||||
return "ip6"
|
|
||||||
return "ip"
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return "hostname"
|
return "hostname"
|
||||||
|
|
||||||
|
if ip_address.version == 6:
|
||||||
|
return "ip6"
|
||||||
|
return "ip"
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
|
|
@ -37,17 +37,17 @@ string_type_validator = dpt_subclass_validator(DPTString)
|
||||||
|
|
||||||
def ga_validator(value: Any) -> str | int:
|
def ga_validator(value: Any) -> str | int:
|
||||||
"""Validate that value is parsable as GroupAddress or InternalGroupAddress."""
|
"""Validate that value is parsable as GroupAddress or InternalGroupAddress."""
|
||||||
if isinstance(value, (str, int)):
|
if not isinstance(value, (str, int)):
|
||||||
|
raise vol.Invalid(
|
||||||
|
f"'{value}' is not a valid KNX group address: Invalid type '{type(value).__name__}'"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
parse_device_group_address(value)
|
parse_device_group_address(value)
|
||||||
return value
|
|
||||||
except CouldNotParseAddress as exc:
|
except CouldNotParseAddress as exc:
|
||||||
raise vol.Invalid(
|
raise vol.Invalid(
|
||||||
f"'{value}' is not a valid KNX group address: {exc.message}"
|
f"'{value}' is not a valid KNX group address: {exc.message}"
|
||||||
) from exc
|
) from exc
|
||||||
raise vol.Invalid(
|
return value
|
||||||
f"'{value}' is not a valid KNX group address: Invalid type '{type(value).__name__}'"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
ga_list_validator = vol.All(
|
ga_list_validator = vol.All(
|
||||||
|
|
|
@ -55,7 +55,6 @@ class LitterRobotHub:
|
||||||
load_robots=load_robots,
|
load_robots=load_robots,
|
||||||
subscribe_for_updates=subscribe_for_updates,
|
subscribe_for_updates=subscribe_for_updates,
|
||||||
)
|
)
|
||||||
return
|
|
||||||
except LitterRobotLoginException as ex:
|
except LitterRobotLoginException as ex:
|
||||||
raise ConfigEntryAuthFailed("Invalid credentials") from ex
|
raise ConfigEntryAuthFailed("Invalid credentials") from ex
|
||||||
except LitterRobotException as ex:
|
except LitterRobotException as ex:
|
||||||
|
|
|
@ -77,7 +77,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
try:
|
try:
|
||||||
async with asyncio.timeout(60):
|
async with asyncio.timeout(60):
|
||||||
await lyric.get_locations()
|
await lyric.get_locations()
|
||||||
return lyric
|
|
||||||
except LyricAuthenticationException as exception:
|
except LyricAuthenticationException as exception:
|
||||||
# Attempt to refresh the token before failing.
|
# Attempt to refresh the token before failing.
|
||||||
# Honeywell appear to have issues keeping tokens saved.
|
# Honeywell appear to have issues keeping tokens saved.
|
||||||
|
@ -87,6 +86,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
raise ConfigEntryAuthFailed from exception
|
raise ConfigEntryAuthFailed from exception
|
||||||
except (LyricException, ClientResponseError) as exception:
|
except (LyricException, ClientResponseError) as exception:
|
||||||
raise UpdateFailed(exception) from exception
|
raise UpdateFailed(exception) from exception
|
||||||
|
return lyric
|
||||||
|
|
||||||
coordinator = DataUpdateCoordinator[Lyric](
|
coordinator = DataUpdateCoordinator[Lyric](
|
||||||
hass,
|
hass,
|
||||||
|
|
|
@ -25,9 +25,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
data = await hass.async_add_executor_job(
|
data = await hass.async_add_executor_job(
|
||||||
meteoclimatic_client.weather_at_station, station_code
|
meteoclimatic_client.weather_at_station, station_code
|
||||||
)
|
)
|
||||||
return data.__dict__
|
|
||||||
except MeteoclimaticError as err:
|
except MeteoclimaticError as err:
|
||||||
raise UpdateFailed(f"Error while retrieving data: {err}") from err
|
raise UpdateFailed(f"Error while retrieving data: {err}") from err
|
||||||
|
return data.__dict__
|
||||||
|
|
||||||
coordinator = DataUpdateCoordinator(
|
coordinator = DataUpdateCoordinator(
|
||||||
hass,
|
hass,
|
||||||
|
|
|
@ -325,8 +325,6 @@ def get_api(entry: dict[str, Any]) -> librouteros.Api:
|
||||||
entry[CONF_PASSWORD],
|
entry[CONF_PASSWORD],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
_LOGGER.debug("Connected to %s successfully", entry[CONF_HOST])
|
|
||||||
return api
|
|
||||||
except (
|
except (
|
||||||
librouteros.exceptions.LibRouterosError,
|
librouteros.exceptions.LibRouterosError,
|
||||||
OSError,
|
OSError,
|
||||||
|
@ -336,3 +334,6 @@ def get_api(entry: dict[str, Any]) -> librouteros.Api:
|
||||||
if "invalid user name or password" in str(api_error):
|
if "invalid user name or password" in str(api_error):
|
||||||
raise LoginError from api_error
|
raise LoginError from api_error
|
||||||
raise CannotConnect from api_error
|
raise CannotConnect from api_error
|
||||||
|
|
||||||
|
_LOGGER.debug("Connected to %s successfully", entry[CONF_HOST])
|
||||||
|
return api
|
||||||
|
|
|
@ -71,9 +71,9 @@ def is_socket_address(value: str) -> str:
|
||||||
"""Validate that value is a valid address."""
|
"""Validate that value is a valid address."""
|
||||||
try:
|
try:
|
||||||
socket.getaddrinfo(value, None)
|
socket.getaddrinfo(value, None)
|
||||||
return value
|
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
raise vol.Invalid("Device is not a valid domain name or ip address") from err
|
raise vol.Invalid("Device is not a valid domain name or ip address") from err
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
async def try_connect(
|
async def try_connect(
|
||||||
|
|
|
@ -72,8 +72,8 @@ class NextBusDataUpdateCoordinator(DataUpdateCoordinator):
|
||||||
# Casting here because we expect dict and not a str due to the input format selected being JSON
|
# Casting here because we expect dict and not a str due to the input format selected being JSON
|
||||||
data = cast(dict[str, Any], data)
|
data = cast(dict[str, Any], data)
|
||||||
self._calc_predictions(data)
|
self._calc_predictions(data)
|
||||||
return data
|
|
||||||
except (NextBusHTTPError, NextBusFormatError) as ex:
|
except (NextBusHTTPError, NextBusFormatError) as ex:
|
||||||
raise UpdateFailed("Failed updating nextbus data", ex) from ex
|
raise UpdateFailed("Failed updating nextbus data", ex) from ex
|
||||||
|
return data
|
||||||
|
|
||||||
return await self.hass.async_add_executor_job(_update_data)
|
return await self.hass.async_add_executor_job(_update_data)
|
||||||
|
|
|
@ -418,13 +418,13 @@ class LeafDataStore:
|
||||||
server_info = await self.hass.async_add_executor_job(
|
server_info = await self.hass.async_add_executor_job(
|
||||||
self.leaf.get_latest_battery_status
|
self.leaf.get_latest_battery_status
|
||||||
)
|
)
|
||||||
return server_info
|
|
||||||
except CarwingsError:
|
except CarwingsError:
|
||||||
_LOGGER.error("An error occurred getting battery status")
|
_LOGGER.error("An error occurred getting battery status")
|
||||||
return None
|
return None
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
_LOGGER.error("An error occurred parsing response from server")
|
_LOGGER.error("An error occurred parsing response from server")
|
||||||
return None
|
return None
|
||||||
|
return server_info
|
||||||
|
|
||||||
async def async_get_climate(
|
async def async_get_climate(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -109,15 +109,15 @@ class ObihaiServiceSensors(SensorEntity):
|
||||||
LOGGER.info("Connection restored")
|
LOGGER.info("Connection restored")
|
||||||
self._attr_available = True
|
self._attr_available = True
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
except RequestException as exc:
|
except RequestException as exc:
|
||||||
if self.requester.available:
|
if self.requester.available:
|
||||||
LOGGER.warning("Connection failed, Obihai offline? %s", exc)
|
LOGGER.warning("Connection failed, Obihai offline? %s", exc)
|
||||||
except IndexError as exc:
|
self._attr_native_value = None
|
||||||
if self.requester.available:
|
self._attr_available = False
|
||||||
LOGGER.warning("Connection failed, bad response: %s", exc)
|
self.requester.available = False
|
||||||
|
except IndexError as exc:
|
||||||
|
if self.requester.available:
|
||||||
|
LOGGER.warning("Connection failed, bad response: %s", exc)
|
||||||
self._attr_native_value = None
|
self._attr_native_value = None
|
||||||
self._attr_available = False
|
self._attr_available = False
|
||||||
self.requester.available = False
|
self.requester.available = False
|
||||||
|
|
|
@ -218,12 +218,13 @@ class ONVIFDevice:
|
||||||
try:
|
try:
|
||||||
await device_mgmt.SetSystemDateAndTime(dt_param)
|
await device_mgmt.SetSystemDateAndTime(dt_param)
|
||||||
LOGGER.debug("%s: SetSystemDateAndTime: success", self.name)
|
LOGGER.debug("%s: SetSystemDateAndTime: success", self.name)
|
||||||
return
|
|
||||||
# Some cameras don't support setting the timezone and will throw an IndexError
|
# Some cameras don't support setting the timezone and will throw an IndexError
|
||||||
# if we try to set it. If we get an error, try again without the timezone.
|
# if we try to set it. If we get an error, try again without the timezone.
|
||||||
except (IndexError, Fault):
|
except (IndexError, Fault):
|
||||||
if idx == timezone_max_idx:
|
if idx == timezone_max_idx:
|
||||||
raise
|
raise
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
async def async_check_date_and_time(self) -> None:
|
async def async_check_date_and_time(self) -> None:
|
||||||
"""Warns if device and system date not synced."""
|
"""Warns if device and system date not synced."""
|
||||||
|
|
|
@ -221,9 +221,9 @@ async def async_parse_field_detector(uid: str, msg) -> Event | None:
|
||||||
None,
|
None,
|
||||||
payload.Data.SimpleItem[0].Value == "true",
|
payload.Data.SimpleItem[0].Value == "true",
|
||||||
)
|
)
|
||||||
return evt
|
|
||||||
except (AttributeError, KeyError):
|
except (AttributeError, KeyError):
|
||||||
return None
|
return None
|
||||||
|
return evt
|
||||||
|
|
||||||
|
|
||||||
@PARSERS.register("tns1:RuleEngine/CellMotionDetector/Motion")
|
@PARSERS.register("tns1:RuleEngine/CellMotionDetector/Motion")
|
||||||
|
|
|
@ -135,8 +135,6 @@ def _decrypt_payload(secret, topic, ciphertext):
|
||||||
try:
|
try:
|
||||||
message = decrypt(ciphertext, key)
|
message = decrypt(ciphertext, key)
|
||||||
message = message.decode("utf-8")
|
message = message.decode("utf-8")
|
||||||
_LOGGER.debug("Decrypted payload: %s", message)
|
|
||||||
return message
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
(
|
(
|
||||||
|
@ -146,6 +144,8 @@ def _decrypt_payload(secret, topic, ciphertext):
|
||||||
topic,
|
topic,
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
_LOGGER.debug("Decrypted payload: %s", message)
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
def encrypt_message(secret, topic, message):
|
def encrypt_message(secret, topic, message):
|
||||||
|
|
|
@ -247,9 +247,6 @@ class Remote:
|
||||||
"""Handle errors from func, set available and reconnect if needed."""
|
"""Handle errors from func, set available and reconnect if needed."""
|
||||||
try:
|
try:
|
||||||
result = await self._hass.async_add_executor_job(func, *args)
|
result = await self._hass.async_add_executor_job(func, *args)
|
||||||
self.state = STATE_ON
|
|
||||||
self.available = True
|
|
||||||
return result
|
|
||||||
except EncryptionRequired:
|
except EncryptionRequired:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"The connection couldn't be encrypted. Please reconfigure your TV"
|
"The connection couldn't be encrypted. Please reconfigure your TV"
|
||||||
|
@ -260,12 +257,18 @@ class Remote:
|
||||||
self.state = STATE_OFF
|
self.state = STATE_OFF
|
||||||
self.available = True
|
self.available = True
|
||||||
await self.async_create_remote_control()
|
await self.async_create_remote_control()
|
||||||
|
return None
|
||||||
except (URLError, OSError) as err:
|
except (URLError, OSError) as err:
|
||||||
_LOGGER.debug("An error occurred: %s", err)
|
_LOGGER.debug("An error occurred: %s", err)
|
||||||
self.state = STATE_OFF
|
self.state = STATE_OFF
|
||||||
self.available = self._on_action is not None
|
self.available = self._on_action is not None
|
||||||
await self.async_create_remote_control()
|
await self.async_create_remote_control()
|
||||||
|
return None
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
_LOGGER.exception("An unknown error occurred")
|
_LOGGER.exception("An unknown error occurred")
|
||||||
self.state = STATE_OFF
|
self.state = STATE_OFF
|
||||||
self.available = self._on_action is not None
|
self.available = self._on_action is not None
|
||||||
|
return None
|
||||||
|
self.state = STATE_ON
|
||||||
|
self.available = True
|
||||||
|
return result
|
||||||
|
|
|
@ -50,14 +50,14 @@ class PicnicUpdateCoordinator(DataUpdateCoordinator):
|
||||||
|
|
||||||
# Update the auth token in the config entry if applicable
|
# Update the auth token in the config entry if applicable
|
||||||
self._update_auth_token()
|
self._update_auth_token()
|
||||||
|
|
||||||
# Return the fetched data
|
|
||||||
return data
|
|
||||||
except ValueError as error:
|
except ValueError as error:
|
||||||
raise UpdateFailed(f"API response was malformed: {error}") from error
|
raise UpdateFailed(f"API response was malformed: {error}") from error
|
||||||
except PicnicAuthError as error:
|
except PicnicAuthError as error:
|
||||||
raise ConfigEntryAuthFailed from error
|
raise ConfigEntryAuthFailed from error
|
||||||
|
|
||||||
|
# Return the fetched data
|
||||||
|
return data
|
||||||
|
|
||||||
def fetch_data(self):
|
def fetch_data(self):
|
||||||
"""Fetch the data from the Picnic API and return a flat dict with only needed sensor data."""
|
"""Fetch the data from the Picnic API and return a flat dict with only needed sensor data."""
|
||||||
# Fetch from the API and pre-process the data
|
# Fetch from the API and pre-process the data
|
||||||
|
|
|
@ -140,7 +140,6 @@ class PingDataSubProcess(PingData):
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
assert match is not None
|
assert match is not None
|
||||||
rtt_min, rtt_avg, rtt_max, rtt_mdev = match.groups()
|
rtt_min, rtt_avg, rtt_max, rtt_mdev = match.groups()
|
||||||
return {"min": rtt_min, "avg": rtt_avg, "max": rtt_max, "mdev": rtt_mdev}
|
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Timed out running command: `%s`, after: %ss",
|
"Timed out running command: `%s`, after: %ss",
|
||||||
|
@ -155,6 +154,7 @@ class PingDataSubProcess(PingData):
|
||||||
return None
|
return None
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
return {"min": rtt_min, "avg": rtt_avg, "max": rtt_max, "mdev": rtt_mdev}
|
||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
"""Retrieve the latest details from the host."""
|
"""Retrieve the latest details from the host."""
|
||||||
|
|
|
@ -35,11 +35,11 @@ async def validate_input(hass: HomeAssistant, data):
|
||||||
auth = Auth(session, data[CONF_USERNAME], data[CONF_PASSWORD], data[CONF_COUNTRY])
|
auth = Auth(session, data[CONF_USERNAME], data[CONF_PASSWORD], data[CONF_COUNTRY])
|
||||||
try:
|
try:
|
||||||
contracts = await Installation.list(auth)
|
contracts = await Installation.list(auth)
|
||||||
return auth, contracts
|
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
raise InvalidAuth from ConnectionRefusedError
|
raise InvalidAuth from ConnectionRefusedError
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
raise CannotConnect from ConnectionError
|
raise CannotConnect from ConnectionError
|
||||||
|
return auth, contracts
|
||||||
|
|
||||||
|
|
||||||
class ProsegurConfigFlow(ConfigFlow, domain=DOMAIN):
|
class ProsegurConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
|
|
|
@ -43,6 +43,9 @@ def get_stream_source(guid, client):
|
||||||
"""Get channel stream source."""
|
"""Get channel stream source."""
|
||||||
try:
|
try:
|
||||||
resp = client.get_channel_live_stream(guid, protocol="rtsp")
|
resp = client.get_channel_live_stream(guid, protocol="rtsp")
|
||||||
|
except QVRResponseError as ex:
|
||||||
|
_LOGGER.error(ex)
|
||||||
|
return None
|
||||||
|
|
||||||
full_url = resp["resourceUris"]
|
full_url = resp["resourceUris"]
|
||||||
|
|
||||||
|
@ -52,10 +55,6 @@ def get_stream_source(guid, client):
|
||||||
|
|
||||||
return f"{protocol}{auth}{url}"
|
return f"{protocol}{auth}{url}"
|
||||||
|
|
||||||
except QVRResponseError as ex:
|
|
||||||
_LOGGER.error(ex)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class QVRProCamera(Camera):
|
class QVRProCamera(Camera):
|
||||||
"""Representation of a QVR Pro camera."""
|
"""Representation of a QVR Pro camera."""
|
||||||
|
|
|
@ -1179,7 +1179,6 @@ class Recorder(threading.Thread):
|
||||||
while tries <= self.db_max_retries:
|
while tries <= self.db_max_retries:
|
||||||
try:
|
try:
|
||||||
self._commit_event_session()
|
self._commit_event_session()
|
||||||
return
|
|
||||||
except (exc.InternalError, exc.OperationalError) as err:
|
except (exc.InternalError, exc.OperationalError) as err:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"%s: Error executing query: %s. (retrying in %s seconds)",
|
"%s: Error executing query: %s. (retrying in %s seconds)",
|
||||||
|
@ -1192,6 +1191,8 @@ class Recorder(threading.Thread):
|
||||||
|
|
||||||
tries += 1
|
tries += 1
|
||||||
time.sleep(self.db_retry_wait)
|
time.sleep(self.db_retry_wait)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
def _commit_event_session(self) -> None:
|
def _commit_event_session(self) -> None:
|
||||||
assert self.event_session is not None
|
assert self.event_session is not None
|
||||||
|
|
|
@ -341,10 +341,10 @@ def _execute_or_collect_error(
|
||||||
with session_scope(session=session_maker()) as session:
|
with session_scope(session=session_maker()) as session:
|
||||||
try:
|
try:
|
||||||
session.connection().execute(text(query))
|
session.connection().execute(text(query))
|
||||||
return True
|
|
||||||
except SQLAlchemyError as err:
|
except SQLAlchemyError as err:
|
||||||
errors.append(str(err))
|
errors.append(str(err))
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _drop_index(
|
def _drop_index(
|
||||||
|
@ -439,11 +439,12 @@ def _add_columns(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return
|
|
||||||
except (InternalError, OperationalError, ProgrammingError):
|
except (InternalError, OperationalError, ProgrammingError):
|
||||||
# Some engines support adding all columns at once,
|
# Some engines support adding all columns at once,
|
||||||
# this error is when they don't
|
# this error is when they don't
|
||||||
_LOGGER.info("Unable to use quick column add. Adding 1 by 1")
|
_LOGGER.info("Unable to use quick column add. Adding 1 by 1")
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
for column_def in columns_def:
|
for column_def in columns_def:
|
||||||
with session_scope(session=session_maker()) as session:
|
with session_scope(session=session_maker()) as session:
|
||||||
|
@ -510,9 +511,10 @@ def _modify_columns(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return
|
|
||||||
except (InternalError, OperationalError):
|
except (InternalError, OperationalError):
|
||||||
_LOGGER.info("Unable to use quick column modify. Modifying 1 by 1")
|
_LOGGER.info("Unable to use quick column modify. Modifying 1 by 1")
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
for column_def in columns_def:
|
for column_def in columns_def:
|
||||||
with session_scope(session=session_maker()) as session:
|
with session_scope(session=session_maker()) as session:
|
||||||
|
|
|
@ -641,7 +641,6 @@ def _insert_statistics(
|
||||||
try:
|
try:
|
||||||
stat = table.from_stats(metadata_id, statistic)
|
stat = table.from_stats(metadata_id, statistic)
|
||||||
session.add(stat)
|
session.add(stat)
|
||||||
return stat
|
|
||||||
except SQLAlchemyError:
|
except SQLAlchemyError:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Unexpected exception when inserting statistics %s:%s ",
|
"Unexpected exception when inserting statistics %s:%s ",
|
||||||
|
@ -649,6 +648,7 @@ def _insert_statistics(
|
||||||
statistic,
|
statistic,
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
return stat
|
||||||
|
|
||||||
|
|
||||||
def _update_statistics(
|
def _update_statistics(
|
||||||
|
|
|
@ -192,13 +192,14 @@ def execute(
|
||||||
elapsed,
|
elapsed,
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
|
||||||
except SQLAlchemyError as err:
|
except SQLAlchemyError as err:
|
||||||
_LOGGER.error("Error executing query: %s", err)
|
_LOGGER.error("Error executing query: %s", err)
|
||||||
|
|
||||||
if tryno == RETRIES - 1:
|
if tryno == RETRIES - 1:
|
||||||
raise
|
raise
|
||||||
time.sleep(QUERY_RETRY_WAIT)
|
time.sleep(QUERY_RETRY_WAIT)
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
|
||||||
# Unreachable
|
# Unreachable
|
||||||
raise RuntimeError # pragma: no cover
|
raise RuntimeError # pragma: no cover
|
||||||
|
@ -685,7 +686,6 @@ def database_job_retry_wrapper(
|
||||||
for attempt in range(attempts):
|
for attempt in range(attempts):
|
||||||
try:
|
try:
|
||||||
job(instance, *args, **kwargs)
|
job(instance, *args, **kwargs)
|
||||||
return
|
|
||||||
except OperationalError as err:
|
except OperationalError as err:
|
||||||
if attempt == attempts - 1 or not _is_retryable_error(
|
if attempt == attempts - 1 or not _is_retryable_error(
|
||||||
instance, err
|
instance, err
|
||||||
|
@ -697,6 +697,8 @@ def database_job_retry_wrapper(
|
||||||
)
|
)
|
||||||
time.sleep(instance.db_retry_wait)
|
time.sleep(instance.db_retry_wait)
|
||||||
# Failed with retryable error
|
# Failed with retryable error
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,6 @@ class RenaultDataUpdateCoordinator(DataUpdateCoordinator[T]):
|
||||||
try:
|
try:
|
||||||
async with _PARALLEL_SEMAPHORE:
|
async with _PARALLEL_SEMAPHORE:
|
||||||
data = await self.update_method()
|
data = await self.update_method()
|
||||||
self._has_already_worked = True
|
|
||||||
return data
|
|
||||||
|
|
||||||
except AccessDeniedException as err:
|
except AccessDeniedException as err:
|
||||||
# This can mean both a temporary error or a permanent error. If it has
|
# This can mean both a temporary error or a permanent error. If it has
|
||||||
|
@ -76,6 +74,9 @@ class RenaultDataUpdateCoordinator(DataUpdateCoordinator[T]):
|
||||||
# Other Renault errors.
|
# Other Renault errors.
|
||||||
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
||||||
|
|
||||||
|
self._has_already_worked = True
|
||||||
|
return data
|
||||||
|
|
||||||
async def async_config_entry_first_refresh(self) -> None:
|
async def async_config_entry_first_refresh(self) -> None:
|
||||||
"""Refresh data for the first time when a config entry is setup.
|
"""Refresh data for the first time when a config entry is setup.
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,10 @@ class RokuDataUpdateCoordinator(DataUpdateCoordinator[Device]):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = await self.roku.update(full_update=full_update)
|
data = await self.roku.update(full_update=full_update)
|
||||||
|
except RokuError as error:
|
||||||
|
raise UpdateFailed(f"Invalid response from API: {error}") from error
|
||||||
|
|
||||||
if full_update:
|
if full_update:
|
||||||
self.last_full_update = utcnow()
|
self.last_full_update = utcnow()
|
||||||
|
|
||||||
return data
|
return data
|
||||||
except RokuError as error:
|
|
||||||
raise UpdateFailed(f"Invalid response from API: {error}") from error
|
|
||||||
|
|
|
@ -39,10 +39,10 @@ class RymProDataUpdateCoordinator(DataUpdateCoordinator[dict[int, dict]]):
|
||||||
meter["consumption_forecast"] = await self.rympro.consumption_forecast(
|
meter["consumption_forecast"] = await self.rympro.consumption_forecast(
|
||||||
meter_id
|
meter_id
|
||||||
)
|
)
|
||||||
return meters
|
|
||||||
except UnauthorizedError as error:
|
except UnauthorizedError as error:
|
||||||
assert self.config_entry
|
assert self.config_entry
|
||||||
await self.hass.config_entries.async_reload(self.config_entry.entry_id)
|
await self.hass.config_entries.async_reload(self.config_entry.entry_id)
|
||||||
raise UpdateFailed(error) from error
|
raise UpdateFailed(error) from error
|
||||||
except (CannotConnectError, OperationError) as error:
|
except (CannotConnectError, OperationError) as error:
|
||||||
raise UpdateFailed(error) from error
|
raise UpdateFailed(error) from error
|
||||||
|
return meters
|
||||||
|
|
|
@ -135,12 +135,12 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
service_response["stdout"] = stdout_data.decode("utf-8").strip()
|
service_response["stdout"] = stdout_data.decode("utf-8").strip()
|
||||||
if stderr_data:
|
if stderr_data:
|
||||||
service_response["stderr"] = stderr_data.decode("utf-8").strip()
|
service_response["stderr"] = stderr_data.decode("utf-8").strip()
|
||||||
return service_response
|
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Unable to handle non-utf8 output of command: `%s`", cmd
|
"Unable to handle non-utf8 output of command: `%s`", cmd
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
|
return service_response
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for name in conf:
|
for name in conf:
|
||||||
|
|
|
@ -210,7 +210,7 @@ async def create_sms_gateway(config, hass):
|
||||||
_LOGGER.error("Failed to initialize, error %s", exc)
|
_LOGGER.error("Failed to initialize, error %s", exc)
|
||||||
await gateway.terminate_async()
|
await gateway.terminate_async()
|
||||||
return None
|
return None
|
||||||
return gateway
|
|
||||||
except gammu.GSMError as exc:
|
except gammu.GSMError as exc:
|
||||||
_LOGGER.error("Failed to create async worker, error %s", exc)
|
_LOGGER.error("Failed to create async worker, error %s", exc)
|
||||||
return None
|
return None
|
||||||
|
return gateway
|
||||||
|
|
|
@ -44,7 +44,6 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
"""Check if we can connect to the Solar-Log device."""
|
"""Check if we can connect to the Solar-Log device."""
|
||||||
try:
|
try:
|
||||||
await self.hass.async_add_executor_job(SolarLog, host)
|
await self.hass.async_add_executor_job(SolarLog, host)
|
||||||
return True
|
|
||||||
except (OSError, HTTPError, Timeout):
|
except (OSError, HTTPError, Timeout):
|
||||||
self._errors[CONF_HOST] = "cannot_connect"
|
self._errors[CONF_HOST] = "cannot_connect"
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
|
@ -52,6 +51,7 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
host,
|
host,
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def async_step_user(self, user_input=None):
|
async def async_step_user(self, user_input=None):
|
||||||
"""Step when user initializes a integration."""
|
"""Step when user initializes a integration."""
|
||||||
|
|
|
@ -101,8 +101,6 @@ def spotify_exception_handler(
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
try:
|
try:
|
||||||
result = func(self, *args, **kwargs)
|
result = func(self, *args, **kwargs)
|
||||||
self._attr_available = True
|
|
||||||
return result
|
|
||||||
except requests.RequestException:
|
except requests.RequestException:
|
||||||
self._attr_available = False
|
self._attr_available = False
|
||||||
return None
|
return None
|
||||||
|
@ -111,6 +109,8 @@ def spotify_exception_handler(
|
||||||
if exc.reason == "NO_ACTIVE_DEVICE":
|
if exc.reason == "NO_ACTIVE_DEVICE":
|
||||||
raise HomeAssistantError("No active playback device found") from None
|
raise HomeAssistantError("No active playback device found") from None
|
||||||
raise HomeAssistantError(f"Spotify error: {exc.reason}") from exc
|
raise HomeAssistantError(f"Spotify error: {exc.reason}") from exc
|
||||||
|
self._attr_available = True
|
||||||
|
return result
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
|
@ -735,10 +735,11 @@ async def _async_find_next_available_port(source: AddressTupleVXType) -> int:
|
||||||
addr = (source[0],) + (port,) + source[2:]
|
addr = (source[0],) + (port,) + source[2:]
|
||||||
try:
|
try:
|
||||||
test_socket.bind(addr)
|
test_socket.bind(addr)
|
||||||
return port
|
|
||||||
except OSError:
|
except OSError:
|
||||||
if port == UPNP_SERVER_MAX_PORT - 1:
|
if port == UPNP_SERVER_MAX_PORT - 1:
|
||||||
raise
|
raise
|
||||||
|
else:
|
||||||
|
return port
|
||||||
|
|
||||||
raise RuntimeError("unreachable")
|
raise RuntimeError("unreachable")
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
)
|
)
|
||||||
if not client.check_credentials():
|
if not client.check_credentials():
|
||||||
raise ConfigEntryError
|
raise ConfigEntryError
|
||||||
return client
|
|
||||||
except PySuezError as ex:
|
except PySuezError as ex:
|
||||||
raise ConfigEntryNotReady from ex
|
raise ConfigEntryNotReady from ex
|
||||||
|
return client
|
||||||
|
|
||||||
hass.data.setdefault(DOMAIN, {})[
|
hass.data.setdefault(DOMAIN, {})[
|
||||||
entry.entry_id
|
entry.entry_id
|
||||||
|
|
|
@ -235,11 +235,12 @@ async def async_check_can_reach_url(
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await session.get(url, timeout=5)
|
await session.get(url, timeout=5)
|
||||||
return "ok"
|
|
||||||
except aiohttp.ClientError:
|
except aiohttp.ClientError:
|
||||||
data = {"type": "failed", "error": "unreachable"}
|
data = {"type": "failed", "error": "unreachable"}
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
data = {"type": "failed", "error": "timeout"}
|
data = {"type": "failed", "error": "timeout"}
|
||||||
|
else:
|
||||||
|
return "ok"
|
||||||
if more_info is not None:
|
if more_info is not None:
|
||||||
data["more_info"] = more_info
|
data["more_info"] = more_info
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -149,7 +149,6 @@ class TcpEntity(Entity):
|
||||||
if value_template is not None:
|
if value_template is not None:
|
||||||
try:
|
try:
|
||||||
self._state = value_template.render(parse_result=False, value=value)
|
self._state = value_template.render(parse_result=False, value=value)
|
||||||
return
|
|
||||||
except TemplateError:
|
except TemplateError:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Unable to render template of %r with value: %r",
|
"Unable to render template of %r with value: %r",
|
||||||
|
@ -157,5 +156,6 @@ class TcpEntity(Entity):
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
return
|
||||||
|
|
||||||
self._state = value
|
self._state = value
|
||||||
|
|
|
@ -687,11 +687,12 @@ class TelegramNotificationService:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Update last message: out_type:%s, out=%s", type(out), out
|
"Update last message: out_type:%s, out=%s", type(out), out
|
||||||
)
|
)
|
||||||
return out
|
|
||||||
except TelegramError as exc:
|
except TelegramError as exc:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"%s: %s. Args: %s, kwargs: %s", msg_error, exc, args_msg, kwargs_msg
|
"%s: %s. Args: %s, kwargs: %s", msg_error, exc, args_msg, kwargs_msg
|
||||||
)
|
)
|
||||||
|
return None
|
||||||
|
return out
|
||||||
|
|
||||||
async def send_message(self, message="", target=None, **kwargs):
|
async def send_message(self, message="", target=None, **kwargs):
|
||||||
"""Send a message to one or multiple pre-allowed chat IDs."""
|
"""Send a message to one or multiple pre-allowed chat IDs."""
|
||||||
|
|
|
@ -267,9 +267,6 @@ async def get_api(
|
||||||
path=path,
|
path=path,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
_LOGGER.debug("Successfully connected to %s", host)
|
|
||||||
return api
|
|
||||||
|
|
||||||
except TransmissionAuthError as error:
|
except TransmissionAuthError as error:
|
||||||
_LOGGER.error("Credentials for Transmission client are not valid")
|
_LOGGER.error("Credentials for Transmission client are not valid")
|
||||||
raise AuthenticationError from error
|
raise AuthenticationError from error
|
||||||
|
@ -279,3 +276,5 @@ async def get_api(
|
||||||
except TransmissionError as error:
|
except TransmissionError as error:
|
||||||
_LOGGER.error(error)
|
_LOGGER.error(error)
|
||||||
raise UnknownError from error
|
raise UnknownError from error
|
||||||
|
_LOGGER.debug("Successfully connected to %s", host)
|
||||||
|
return api
|
||||||
|
|
|
@ -56,7 +56,6 @@ async def get_unifi_api(
|
||||||
try:
|
try:
|
||||||
async with asyncio.timeout(10):
|
async with asyncio.timeout(10):
|
||||||
await api.login()
|
await api.login()
|
||||||
return api
|
|
||||||
|
|
||||||
except aiounifi.Unauthorized as err:
|
except aiounifi.Unauthorized as err:
|
||||||
LOGGER.warning(
|
LOGGER.warning(
|
||||||
|
@ -90,3 +89,5 @@ async def get_unifi_api(
|
||||||
except aiounifi.AiounifiException as err:
|
except aiounifi.AiounifiException as err:
|
||||||
LOGGER.exception("Unknown UniFi Network communication error occurred: %s", err)
|
LOGGER.exception("Unknown UniFi Network communication error occurred: %s", err)
|
||||||
raise AuthenticationRequired from err
|
raise AuthenticationRequired from err
|
||||||
|
|
||||||
|
return api
|
||||||
|
|
|
@ -408,10 +408,10 @@ class UpdateEntity(
|
||||||
|
|
||||||
try:
|
try:
|
||||||
newer = _version_is_newer(latest_version, installed_version)
|
newer = _version_is_newer(latest_version, installed_version)
|
||||||
return STATE_ON if newer else STATE_OFF
|
|
||||||
except AwesomeVersionCompareException:
|
except AwesomeVersionCompareException:
|
||||||
# Can't compare versions, already tried exact match
|
# Can't compare versions, already tried exact match
|
||||||
return STATE_ON
|
return STATE_ON
|
||||||
|
return STATE_ON if newer else STATE_OFF
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -175,11 +175,10 @@ class ValloxServiceHandler:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self._client.set_fan_speed(Profile.HOME, fan_speed)
|
await self._client.set_fan_speed(Profile.HOME, fan_speed)
|
||||||
return True
|
|
||||||
|
|
||||||
except ValloxApiException as err:
|
except ValloxApiException as err:
|
||||||
_LOGGER.error("Error setting fan speed for Home profile: %s", err)
|
_LOGGER.error("Error setting fan speed for Home profile: %s", err)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def async_set_profile_fan_speed_away(
|
async def async_set_profile_fan_speed_away(
|
||||||
self, fan_speed: int = DEFAULT_FAN_SPEED_AWAY
|
self, fan_speed: int = DEFAULT_FAN_SPEED_AWAY
|
||||||
|
@ -189,11 +188,10 @@ class ValloxServiceHandler:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self._client.set_fan_speed(Profile.AWAY, fan_speed)
|
await self._client.set_fan_speed(Profile.AWAY, fan_speed)
|
||||||
return True
|
|
||||||
|
|
||||||
except ValloxApiException as err:
|
except ValloxApiException as err:
|
||||||
_LOGGER.error("Error setting fan speed for Away profile: %s", err)
|
_LOGGER.error("Error setting fan speed for Away profile: %s", err)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def async_set_profile_fan_speed_boost(
|
async def async_set_profile_fan_speed_boost(
|
||||||
self, fan_speed: int = DEFAULT_FAN_SPEED_BOOST
|
self, fan_speed: int = DEFAULT_FAN_SPEED_BOOST
|
||||||
|
@ -203,11 +201,10 @@ class ValloxServiceHandler:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self._client.set_fan_speed(Profile.BOOST, fan_speed)
|
await self._client.set_fan_speed(Profile.BOOST, fan_speed)
|
||||||
return True
|
|
||||||
|
|
||||||
except ValloxApiException as err:
|
except ValloxApiException as err:
|
||||||
_LOGGER.error("Error setting fan speed for Boost profile: %s", err)
|
_LOGGER.error("Error setting fan speed for Boost profile: %s", err)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def async_handle(self, call: ServiceCall) -> None:
|
async def async_handle(self, call: ServiceCall) -> None:
|
||||||
"""Dispatch a service call."""
|
"""Dispatch a service call."""
|
||||||
|
|
|
@ -84,11 +84,13 @@ async def async_http_request(hass, uri):
|
||||||
if req.status != HTTPStatus.OK:
|
if req.status != HTTPStatus.OK:
|
||||||
return {"error": req.status}
|
return {"error": req.status}
|
||||||
json_response = await req.json()
|
json_response = await req.json()
|
||||||
return json_response
|
|
||||||
except (TimeoutError, aiohttp.ClientError) as exc:
|
except (TimeoutError, aiohttp.ClientError) as exc:
|
||||||
_LOGGER.error("Cannot connect to ViaggiaTreno API endpoint: %s", exc)
|
_LOGGER.error("Cannot connect to ViaggiaTreno API endpoint: %s", exc)
|
||||||
|
return None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
_LOGGER.error("Received non-JSON data from ViaggiaTreno API endpoint")
|
_LOGGER.error("Received non-JSON data from ViaggiaTreno API endpoint")
|
||||||
|
return None
|
||||||
|
return json_response
|
||||||
|
|
||||||
|
|
||||||
class ViaggiaTrenoSensor(SensorEntity):
|
class ViaggiaTrenoSensor(SensorEntity):
|
||||||
|
|
|
@ -35,13 +35,14 @@ def is_supported(
|
||||||
"""Check if the PyViCare device supports the requested sensor."""
|
"""Check if the PyViCare device supports the requested sensor."""
|
||||||
try:
|
try:
|
||||||
entity_description.value_getter(vicare_device)
|
entity_description.value_getter(vicare_device)
|
||||||
_LOGGER.debug("Found entity %s", name)
|
|
||||||
return True
|
|
||||||
except PyViCareNotSupportedFeatureError:
|
except PyViCareNotSupportedFeatureError:
|
||||||
_LOGGER.debug("Feature not supported %s", name)
|
_LOGGER.debug("Feature not supported %s", name)
|
||||||
|
return False
|
||||||
except AttributeError as error:
|
except AttributeError as error:
|
||||||
_LOGGER.debug("Feature not supported %s: %s", name, error)
|
_LOGGER.debug("Feature not supported %s: %s", name, error)
|
||||||
return False
|
return False
|
||||||
|
_LOGGER.debug("Found entity %s", name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_burners(device: PyViCareDevice) -> list[PyViCareHeatingDeviceComponent]:
|
def get_burners(device: PyViCareDevice) -> list[PyViCareHeatingDeviceComponent]:
|
||||||
|
|
|
@ -178,10 +178,10 @@ async def async_handle_webhook(
|
||||||
response: Response | None = await webhook["handler"](hass, webhook_id, request)
|
response: Response | None = await webhook["handler"](hass, webhook_id, request)
|
||||||
if response is None:
|
if response is None:
|
||||||
response = Response(status=HTTPStatus.OK)
|
response = Response(status=HTTPStatus.OK)
|
||||||
return response
|
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
_LOGGER.exception("Error processing webhook %s", webhook_id)
|
_LOGGER.exception("Error processing webhook %s", webhook_id)
|
||||||
return Response(status=HTTPStatus.OK)
|
return Response(status=HTTPStatus.OK)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
|
|
@ -94,9 +94,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
if bulb.power_monitoring is not False:
|
if bulb.power_monitoring is not False:
|
||||||
power: float | None = await bulb.get_power()
|
power: float | None = await bulb.get_power()
|
||||||
return power
|
return power
|
||||||
return None
|
|
||||||
except WIZ_EXCEPTIONS as ex:
|
except WIZ_EXCEPTIONS as ex:
|
||||||
raise UpdateFailed(f"Failed to update device at {ip_address}: {ex}") from ex
|
raise UpdateFailed(f"Failed to update device at {ip_address}: {ex}") from ex
|
||||||
|
return None
|
||||||
|
|
||||||
coordinator = DataUpdateCoordinator(
|
coordinator = DataUpdateCoordinator(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
|
|
|
@ -150,16 +150,15 @@ class XiaomiCoordinatedMiioEntity(CoordinatorEntity[_T]):
|
||||||
result = await self.hass.async_add_executor_job(
|
result = await self.hass.async_add_executor_job(
|
||||||
partial(func, *args, **kwargs)
|
partial(func, *args, **kwargs)
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER.debug("Response received from miio device: %s", result)
|
|
||||||
|
|
||||||
return True
|
|
||||||
except DeviceException as exc:
|
except DeviceException as exc:
|
||||||
if self.available:
|
if self.available:
|
||||||
_LOGGER.error(mask_error, exc)
|
_LOGGER.error(mask_error, exc)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
_LOGGER.debug("Response received from miio device: %s", result)
|
||||||
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _extract_value_from_attribute(cls, state, attribute):
|
def _extract_value_from_attribute(cls, state, attribute):
|
||||||
value = getattr(state, attribute)
|
value = getattr(state, attribute)
|
||||||
|
|
|
@ -292,10 +292,6 @@ class XiaomiPhilipsAbstractLight(XiaomiMiioEntity, LightEntity):
|
||||||
result = await self.hass.async_add_executor_job(
|
result = await self.hass.async_add_executor_job(
|
||||||
partial(func, *args, **kwargs)
|
partial(func, *args, **kwargs)
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER.debug("Response received from light: %s", result)
|
|
||||||
|
|
||||||
return result == SUCCESS
|
|
||||||
except DeviceException as exc:
|
except DeviceException as exc:
|
||||||
if self._available:
|
if self._available:
|
||||||
_LOGGER.error(mask_error, exc)
|
_LOGGER.error(mask_error, exc)
|
||||||
|
@ -303,6 +299,9 @@ class XiaomiPhilipsAbstractLight(XiaomiMiioEntity, LightEntity):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
_LOGGER.debug("Response received from light: %s", result)
|
||||||
|
return result == SUCCESS
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the light on."""
|
"""Turn the light on."""
|
||||||
if ATTR_BRIGHTNESS in kwargs:
|
if ATTR_BRIGHTNESS in kwargs:
|
||||||
|
|
|
@ -225,9 +225,9 @@ class XiaomiMiioRemote(RemoteEntity):
|
||||||
"""Return False if device is unreachable, else True."""
|
"""Return False if device is unreachable, else True."""
|
||||||
try:
|
try:
|
||||||
self.device.info()
|
self.device.info()
|
||||||
return True
|
|
||||||
except DeviceException:
|
except DeviceException:
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
|
|
|
@ -805,6 +805,12 @@ class XiaomiPlugGenericSwitch(XiaomiMiioEntity, SwitchEntity):
|
||||||
result = await self.hass.async_add_executor_job(
|
result = await self.hass.async_add_executor_job(
|
||||||
partial(func, *args, **kwargs)
|
partial(func, *args, **kwargs)
|
||||||
)
|
)
|
||||||
|
except DeviceException as exc:
|
||||||
|
if self._available:
|
||||||
|
_LOGGER.error(mask_error, exc)
|
||||||
|
self._available = False
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
_LOGGER.debug("Response received from plug: %s", result)
|
_LOGGER.debug("Response received from plug: %s", result)
|
||||||
|
|
||||||
|
@ -813,12 +819,6 @@ class XiaomiPlugGenericSwitch(XiaomiMiioEntity, SwitchEntity):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return result == SUCCESS
|
return result == SUCCESS
|
||||||
except DeviceException as exc:
|
|
||||||
if self._available:
|
|
||||||
_LOGGER.error(mask_error, exc)
|
|
||||||
self._available = False
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the plug on."""
|
"""Turn the plug on."""
|
||||||
|
|
|
@ -281,10 +281,10 @@ class MiroboVacuum(
|
||||||
try:
|
try:
|
||||||
await self.hass.async_add_executor_job(partial(func, *args, **kwargs))
|
await self.hass.async_add_executor_job(partial(func, *args, **kwargs))
|
||||||
await self.coordinator.async_refresh()
|
await self.coordinator.async_refresh()
|
||||||
return True
|
|
||||||
except DeviceException as exc:
|
except DeviceException as exc:
|
||||||
_LOGGER.error(mask_error, exc)
|
_LOGGER.error(mask_error, exc)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def async_start(self) -> None:
|
async def async_start(self) -> None:
|
||||||
"""Start or resume the cleaning task."""
|
"""Start or resume the cleaning task."""
|
||||||
|
|
|
@ -66,9 +66,9 @@ class ZamgWeather(CoordinatorEntity, WeatherEntity):
|
||||||
value := self.coordinator.data[self.station_id]["TL"]["data"]
|
value := self.coordinator.data[self.station_id]["TL"]["data"]
|
||||||
) is not None:
|
) is not None:
|
||||||
return float(value)
|
return float(value)
|
||||||
return None
|
|
||||||
except (KeyError, ValueError, TypeError):
|
except (KeyError, ValueError, TypeError):
|
||||||
return None
|
return None
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_pressure(self) -> float | None:
|
def native_pressure(self) -> float | None:
|
||||||
|
@ -98,9 +98,9 @@ class ZamgWeather(CoordinatorEntity, WeatherEntity):
|
||||||
value := self.coordinator.data[self.station_id]["FFX"]["data"]
|
value := self.coordinator.data[self.station_id]["FFX"]["data"]
|
||||||
) is not None:
|
) is not None:
|
||||||
return float(value)
|
return float(value)
|
||||||
return None
|
|
||||||
except (KeyError, ValueError, TypeError):
|
except (KeyError, ValueError, TypeError):
|
||||||
return None
|
return None
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wind_bearing(self) -> float | None:
|
def wind_bearing(self) -> float | None:
|
||||||
|
@ -114,6 +114,6 @@ class ZamgWeather(CoordinatorEntity, WeatherEntity):
|
||||||
value := self.coordinator.data[self.station_id]["DDX"]["data"]
|
value := self.coordinator.data[self.station_id]["DDX"]["data"]
|
||||||
) is not None:
|
) is not None:
|
||||||
return float(value)
|
return float(value)
|
||||||
return None
|
|
||||||
except (KeyError, ValueError, TypeError):
|
except (KeyError, ValueError, TypeError):
|
||||||
return None
|
return None
|
||||||
|
return None
|
||||||
|
|
|
@ -789,6 +789,15 @@ class ZHADevice(LogMixin):
|
||||||
response = await cluster.write_attributes(
|
response = await cluster.write_attributes(
|
||||||
{attribute: value}, manufacturer=manufacturer
|
{attribute: value}, manufacturer=manufacturer
|
||||||
)
|
)
|
||||||
|
except zigpy.exceptions.ZigbeeException as exc:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
f"Failed to set attribute: "
|
||||||
|
f"{ATTR_VALUE}: {value} "
|
||||||
|
f"{ATTR_ATTRIBUTE}: {attribute} "
|
||||||
|
f"{ATTR_CLUSTER_ID}: {cluster_id} "
|
||||||
|
f"{ATTR_ENDPOINT_ID}: {endpoint_id}"
|
||||||
|
) from exc
|
||||||
|
|
||||||
self.debug(
|
self.debug(
|
||||||
"set: %s for attr: %s to cluster: %s for ept: %s - res: %s",
|
"set: %s for attr: %s to cluster: %s for ept: %s - res: %s",
|
||||||
value,
|
value,
|
||||||
|
@ -798,14 +807,6 @@ class ZHADevice(LogMixin):
|
||||||
response,
|
response,
|
||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
except zigpy.exceptions.ZigbeeException as exc:
|
|
||||||
raise HomeAssistantError(
|
|
||||||
f"Failed to set attribute: "
|
|
||||||
f"{ATTR_VALUE}: {value} "
|
|
||||||
f"{ATTR_ATTRIBUTE}: {attribute} "
|
|
||||||
f"{ATTR_CLUSTER_ID}: {cluster_id} "
|
|
||||||
f"{ATTR_ENDPOINT_ID}: {endpoint_id}"
|
|
||||||
) from exc
|
|
||||||
|
|
||||||
async def issue_cluster_command(
|
async def issue_cluster_command(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -102,9 +102,9 @@ async def safe_read(
|
||||||
only_cache=only_cache,
|
only_cache=only_cache,
|
||||||
manufacturer=manufacturer,
|
manufacturer=manufacturer,
|
||||||
)
|
)
|
||||||
return result
|
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
return {}
|
return {}
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
async def get_matched_clusters(
|
async def get_matched_clusters(
|
||||||
|
|
|
@ -464,14 +464,12 @@ def _write_default_config(config_dir: str) -> bool:
|
||||||
if not os.path.isfile(scene_yaml_path):
|
if not os.path.isfile(scene_yaml_path):
|
||||||
with open(scene_yaml_path, "w", encoding="utf8"):
|
with open(scene_yaml_path, "w", encoding="utf8"):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
except OSError:
|
except OSError:
|
||||||
print( # noqa: T201
|
print( # noqa: T201
|
||||||
f"Unable to create default configuration file {config_path}"
|
f"Unable to create default configuration file {config_path}"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_hass_config_yaml(hass: HomeAssistant) -> dict:
|
async def async_hass_config_yaml(hass: HomeAssistant) -> dict:
|
||||||
|
|
|
@ -763,8 +763,6 @@ class ConfigEntry:
|
||||||
self._async_set_state(hass, ConfigEntryState.NOT_LOADED, None)
|
self._async_set_state(hass, ConfigEntryState.NOT_LOADED, None)
|
||||||
|
|
||||||
await self._async_process_on_unload(hass)
|
await self._async_process_on_unload(hass)
|
||||||
|
|
||||||
return result
|
|
||||||
except Exception as exc: # pylint: disable=broad-except
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Error unloading entry %s for %s", self.title, integration.domain
|
"Error unloading entry %s for %s", self.title, integration.domain
|
||||||
|
@ -774,6 +772,7 @@ class ConfigEntry:
|
||||||
hass, ConfigEntryState.FAILED_UNLOAD, str(exc) or "Unknown error"
|
hass, ConfigEntryState.FAILED_UNLOAD, str(exc) or "Unknown error"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
return result
|
||||||
|
|
||||||
async def async_remove(self, hass: HomeAssistant) -> None:
|
async def async_remove(self, hass: HomeAssistant) -> None:
|
||||||
"""Invoke remove callback on component."""
|
"""Invoke remove callback on component."""
|
||||||
|
@ -872,12 +871,12 @@ class ConfigEntry:
|
||||||
if result:
|
if result:
|
||||||
# pylint: disable-next=protected-access
|
# pylint: disable-next=protected-access
|
||||||
hass.config_entries._async_schedule_save()
|
hass.config_entries._async_schedule_save()
|
||||||
return result
|
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Error migrating entry %s for %s", self.title, self.domain
|
"Error migrating entry %s for %s", self.title, self.domain
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
return result
|
||||||
|
|
||||||
def add_update_listener(self, listener: UpdateListenerType) -> CALLBACK_TYPE:
|
def add_update_listener(self, listener: UpdateListenerType) -> CALLBACK_TYPE:
|
||||||
"""Listen for when entry is updated.
|
"""Listen for when entry is updated.
|
||||||
|
|
|
@ -2691,9 +2691,10 @@ class Config:
|
||||||
for allowed_path in self.allowlist_external_dirs:
|
for allowed_path in self.allowlist_external_dirs:
|
||||||
try:
|
try:
|
||||||
thepath.relative_to(allowed_path)
|
thepath.relative_to(allowed_path)
|
||||||
return True
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -248,13 +248,13 @@ def is_regex(value: Any) -> re.Pattern[Any]:
|
||||||
"""Validate that a string is a valid regular expression."""
|
"""Validate that a string is a valid regular expression."""
|
||||||
try:
|
try:
|
||||||
r = re.compile(value)
|
r = re.compile(value)
|
||||||
return r
|
|
||||||
except TypeError as err:
|
except TypeError as err:
|
||||||
raise vol.Invalid(
|
raise vol.Invalid(
|
||||||
f"value {value} is of the wrong type for a regular expression"
|
f"value {value} is of the wrong type for a regular expression"
|
||||||
) from err
|
) from err
|
||||||
except re.error as err:
|
except re.error as err:
|
||||||
raise vol.Invalid(f"value {value} is not a valid regular expression") from err
|
raise vol.Invalid(f"value {value} is not a valid regular expression") from err
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
def isfile(value: Any) -> str:
|
def isfile(value: Any) -> str:
|
||||||
|
@ -671,9 +671,9 @@ def template(value: Any | None) -> template_helper.Template:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
template_value.ensure_valid()
|
template_value.ensure_valid()
|
||||||
return template_value
|
|
||||||
except TemplateError as ex:
|
except TemplateError as ex:
|
||||||
raise vol.Invalid(f"invalid template ({ex})") from ex
|
raise vol.Invalid(f"invalid template ({ex})") from ex
|
||||||
|
return template_value
|
||||||
|
|
||||||
|
|
||||||
def dynamic_template(value: Any | None) -> template_helper.Template:
|
def dynamic_template(value: Any | None) -> template_helper.Template:
|
||||||
|
@ -693,9 +693,9 @@ def dynamic_template(value: Any | None) -> template_helper.Template:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
template_value.ensure_valid()
|
template_value.ensure_valid()
|
||||||
return template_value
|
|
||||||
except TemplateError as ex:
|
except TemplateError as ex:
|
||||||
raise vol.Invalid(f"invalid template ({ex})") from ex
|
raise vol.Invalid(f"invalid template ({ex})") from ex
|
||||||
|
return template_value
|
||||||
|
|
||||||
|
|
||||||
def template_complex(value: Any) -> Any:
|
def template_complex(value: Any) -> Any:
|
||||||
|
|
|
@ -362,10 +362,6 @@ class EntityPlatform:
|
||||||
pending = self._tasks.copy()
|
pending = self._tasks.copy()
|
||||||
self._tasks.clear()
|
self._tasks.clear()
|
||||||
await asyncio.gather(*pending)
|
await asyncio.gather(*pending)
|
||||||
|
|
||||||
hass.config.components.add(full_name)
|
|
||||||
self._setup_complete = True
|
|
||||||
return True
|
|
||||||
except PlatformNotReady as ex:
|
except PlatformNotReady as ex:
|
||||||
tries += 1
|
tries += 1
|
||||||
wait_time = min(tries, 6) * PLATFORM_NOT_READY_BASE_WAIT_TIME
|
wait_time = min(tries, 6) * PLATFORM_NOT_READY_BASE_WAIT_TIME
|
||||||
|
@ -417,6 +413,10 @@ class EntityPlatform:
|
||||||
self.domain,
|
self.domain,
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
else:
|
||||||
|
hass.config.components.add(full_name)
|
||||||
|
self._setup_complete = True
|
||||||
|
return True
|
||||||
finally:
|
finally:
|
||||||
warn_task.cancel()
|
warn_task.cancel()
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,6 @@ class RegistryEntry:
|
||||||
try:
|
try:
|
||||||
dict_repr = self._as_display_dict
|
dict_repr = self._as_display_dict
|
||||||
json_repr: bytes | None = json_bytes(dict_repr) if dict_repr else None
|
json_repr: bytes | None = json_bytes(dict_repr) if dict_repr else None
|
||||||
return json_repr
|
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Unable to serialize entry %s to JSON. Bad data found at %s",
|
"Unable to serialize entry %s to JSON. Bad data found at %s",
|
||||||
|
@ -252,8 +251,8 @@ class RegistryEntry:
|
||||||
find_paths_unserializable_data(dict_repr, dump=JSON_DUMP)
|
find_paths_unserializable_data(dict_repr, dump=JSON_DUMP)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
return json_repr
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def as_partial_dict(self) -> dict[str, Any]:
|
def as_partial_dict(self) -> dict[str, Any]:
|
||||||
|
|
|
@ -109,7 +109,6 @@ async def async_handle(
|
||||||
try:
|
try:
|
||||||
_LOGGER.info("Triggering intent handler %s", handler)
|
_LOGGER.info("Triggering intent handler %s", handler)
|
||||||
result = await handler.async_handle(intent)
|
result = await handler.async_handle(intent)
|
||||||
return result
|
|
||||||
except vol.Invalid as err:
|
except vol.Invalid as err:
|
||||||
_LOGGER.warning("Received invalid slot info for %s: %s", intent_type, err)
|
_LOGGER.warning("Received invalid slot info for %s: %s", intent_type, err)
|
||||||
raise InvalidSlotInfo(f"Received invalid slot info for {intent_type}") from err
|
raise InvalidSlotInfo(f"Received invalid slot info for {intent_type}") from err
|
||||||
|
@ -117,6 +116,7 @@ async def async_handle(
|
||||||
raise # bubble up intent related errors
|
raise # bubble up intent related errors
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise IntentUnexpectedError(f"Error handling {intent_type}") from err
|
raise IntentUnexpectedError(f"Error handling {intent_type}") from err
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class IntentError(HomeAssistantError):
|
class IntentError(HomeAssistantError):
|
||||||
|
|
|
@ -31,9 +31,9 @@ def is_internal_request(hass: HomeAssistant) -> bool:
|
||||||
get_url(
|
get_url(
|
||||||
hass, allow_external=False, allow_cloud=False, require_current_request=True
|
hass, allow_external=False, allow_cloud=False, require_current_request=True
|
||||||
)
|
)
|
||||||
return True
|
|
||||||
except NoURLAvailableError:
|
except NoURLAvailableError:
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
@bind_hass
|
@bind_hass
|
||||||
|
|
|
@ -166,7 +166,6 @@ async def async_setup_component(
|
||||||
setup_future.set_result(result)
|
setup_future.set_result(result)
|
||||||
if setup_done_future := setup_done_futures.pop(domain, None):
|
if setup_done_future := setup_done_futures.pop(domain, None):
|
||||||
setup_done_future.set_result(result)
|
setup_done_future.set_result(result)
|
||||||
return result
|
|
||||||
except BaseException as err:
|
except BaseException as err:
|
||||||
futures = [setup_future]
|
futures = [setup_future]
|
||||||
if setup_done_future := setup_done_futures.pop(domain, None):
|
if setup_done_future := setup_done_futures.pop(domain, None):
|
||||||
|
@ -185,6 +184,7 @@ async def async_setup_component(
|
||||||
# if there are no concurrent setup attempts
|
# if there are no concurrent setup attempts
|
||||||
await future
|
await future
|
||||||
raise
|
raise
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
async def _async_process_dependencies(
|
async def _async_process_dependencies(
|
||||||
|
|
|
@ -714,8 +714,7 @@ ignore = [
|
||||||
# temporarily disabled
|
# temporarily disabled
|
||||||
"PT019",
|
"PT019",
|
||||||
"TRY002",
|
"TRY002",
|
||||||
"TRY301",
|
"TRY301"
|
||||||
"TRY300"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.lint.flake8-import-conventions.extend-aliases]
|
[tool.ruff.lint.flake8-import-conventions.extend-aliases]
|
||||||
|
|
|
@ -88,11 +88,11 @@ def mock_client(
|
||||||
val = mock_read_char_raw[uuid]
|
val = mock_read_char_raw[uuid]
|
||||||
if isinstance(val, Exception):
|
if isinstance(val, Exception):
|
||||||
raise val
|
raise val
|
||||||
return val
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if default is SENTINEL:
|
if default is SENTINEL:
|
||||||
raise CharacteristicNotFound from KeyError
|
raise CharacteristicNotFound from KeyError
|
||||||
return default
|
return default
|
||||||
|
return val
|
||||||
|
|
||||||
def _all_char():
|
def _all_char():
|
||||||
return set(mock_read_char_raw.keys())
|
return set(mock_read_char_raw.keys())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue