Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quieter but more useful logs for API errors #80

Merged
merged 2 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ repos:
rev: v0.7.0
hooks:
- id: python-typing-update
stages: [manual]
args:
- --py312-plus
- --force
Expand Down
46 changes: 28 additions & 18 deletions custom_components/bestway/bestway/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class BestwayOfflineException(BestwayException):

def __init__(self) -> None:
"""Construct the exception."""
super().__init__("Device is offline")
super().__init__("Server reports device is offline")


class BestwayAuthException(BestwayException):
Expand All @@ -57,37 +57,47 @@ class BestwayAuthException(BestwayException):
class BestwayTokenInvalidException(BestwayAuthException):
"""Auth token is invalid or expired."""

def __init__(self) -> None:
super().__init__("Server reports auth token is invalid or expired")


class BestwayUserDoesNotExistException(BestwayAuthException):
"""User does not exist."""

def __init__(self) -> None:
super().__init__("Server reports user does not exist")


class BestwayIncorrectPasswordException(BestwayAuthException):
"""Password is incorrect."""

def __init__(self) -> None:
super().__init__("Server reports password is incorrect")


async def _raise_for_status(response: ClientResponse) -> None:
"""Raise an exception based on the response."""
if response.ok:
return

# Try to parse out the bestway error code
try:
api_error = await response.json()
except Exception: # pylint: disable=broad-except
response.raise_for_status()

error_code = api_error.get("error_code", 0)
if error_code == 9004:
raise BestwayTokenInvalidException()
if error_code == 9005:
raise BestwayUserDoesNotExistException()
if error_code == 9042:
raise BestwayOfflineException()
if error_code == 9020:
raise BestwayIncorrectPasswordException()

# If we don't understand the error code, provide more detail for debugging
# The API often provides useful error descriptions in JSON format
if response.content_type == "application/json":
try:
api_error = await response.json()
except Exception: # pylint: disable=broad-except
response.raise_for_status()

error_code = api_error.get("error_code", 0)
if error_code == 9004:
raise BestwayTokenInvalidException()
if error_code == 9005:
raise BestwayUserDoesNotExistException()
if error_code == 9042:
raise BestwayOfflineException()
if error_code == 9020:
raise BestwayIncorrectPasswordException()

# If we can't pull out a Bestway error code, provide more detail for debugging
response.raise_for_status()


Expand Down
2 changes: 1 addition & 1 deletion custom_components/bestway/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def is_on(self) -> bool | None:
@property
def available(self) -> bool:
"""Return True, as the connectivity sensor is always available."""
return True
return self.coordinator.last_update_success


class DeviceErrorsSensor(BestwayEntity, BinarySensorEntity):
Expand Down
12 changes: 4 additions & 8 deletions custom_components/bestway/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from logging import getLogger

from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .bestway.api import BestwayApi, BestwayApiResults

Expand All @@ -31,10 +31,6 @@ async def _async_update_data(self) -> BestwayApiResults:
This is the place to pre-process the data to lookup tables
so entities can quickly look up their data.
"""
try:
async with asyncio.timeout(10):
await self.api.refresh_bindings()
return await self.api.fetch_data()
except Exception as err:
_LOGGER.exception("Data update failed")
raise UpdateFailed(f"Error communicating with API: {err}") from err
async with asyncio.timeout(10):
await self.api.refresh_bindings()
return await self.api.fetch_data()
6 changes: 5 additions & 1 deletion custom_components/bestway/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ def status(self) -> BestwayDeviceStatus | None:
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self.bestway_device is not None and self.bestway_device.is_online
return (
self.coordinator.last_update_success
and self.bestway_device is not None
and self.bestway_device.is_online
)