Skip to content

Commit

Permalink
Improve error handling (#3)
Browse files Browse the repository at this point in the history
* Improve error handling

* Improve a bit readme

* Fix checks
  • Loading branch information
hwmland authored Feb 13, 2022
1 parent 2b17c1b commit eedbced
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 53 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ Alternatively you can install it manually by copying the contents of `custom_com
# Setup integration

Add new XMRIG instance configuring name, address and (opion) access token.
It's not possible to add one server twice.

24 changes: 17 additions & 7 deletions custom_components/xmrig/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from homeassistant import config_entries
from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv
from homeassistant.components.rest.data import RestData
from homeassistant.core import callback

from .const import (
Expand All @@ -17,6 +16,7 @@
DATA_CONTROLLER,
DOMAIN,
)
from .restapicall import RestApiCall

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -65,11 +65,11 @@ async def async_step_user(self, user_input: Optional[Dict[str, Any]] = None):
raise ConfigFlowException("address_exists")

resource = user_input[CONF_ADDRESS] + "/2/summary"
token = user_input[CONF_TOKEN]
token = user_input[CONF_TOKEN] if CONF_TOKEN in user_input else None
headers = (
None if token is None else {"Authorization": "Bearer " + token}
)
rest = RestData(
rest = RestApiCall(
self.hass,
"GET",
resource,
Expand All @@ -80,23 +80,33 @@ async def async_step_user(self, user_input: Optional[Dict[str, Any]] = None):
verify_ssl=True,
)
await rest.async_update()
if rest.status == 403:
raise ConfigFlowException("not_authorized")
if rest.data is None:
raise ConfigFlowException("no_answer")
response = json.loads(rest.data)
if "error" in response:
responseError = response["error"]
if responseError == "Unauthorized":
raise ConfigFlowException("not_authorized")
else:
_LOGGER.warning(
"Error received from server: %s", response.error
)
except ConfigFlowException as ex:
_LOGGER.warning("Configuration error: %s", ex.error)
errors["base"] = ex.error
except:
_LOGGER.warning("Unexpected exception")
except Exception as ex:
_LOGGER.warning("Unexpected exception %s", ex)
errors["base"] = "unknown_exception"
raise
if not errors:
# Input is valid, set data.
self.data = user_input
return self.async_create_entry(
title=user_input[CONF_NAME], data=self.data
)

_LOGGER.debug("Show input form...")
_LOGGER.debug("Show input form")
return self.async_show_form(
step_id="user", data_schema=AUTH_SCHEMA, errors=errors
)
9 changes: 5 additions & 4 deletions custom_components/xmrig/hwm_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
from typing import Any, Dict, Optional, List

from homeassistant import config_entries
from homeassistant.components.rest.data import RestData
from homeassistant.const import CONF_NAME
from homeassistant.core import callback
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval

from .restapicall import RestApiCall

_LOGGER = logging.getLogger(__name__)


Expand All @@ -42,7 +43,7 @@ def __init__(
# pylint: disable=assignment-from-none
resource = self._vGetResource(config_entry)
headers = self._vGetHeaders(config_entry)
self._rest = RestData(
self._rest = RestApiCall(
self._hass,
"GET",
resource,
Expand All @@ -55,11 +56,11 @@ def __init__(
self._data: Dict[str, Any] = None

def _vGetResource(self, config_entry: config_entries.ConfigEntry) -> str:
"""Get RestData resource"""
"""Get RestApiCall resource"""
return None

def _vGetHeaders(self, config_entry: config_entries.ConfigEntry) -> any: # @type
"""Get RestData headers"""
"""Get RestApiCall headers"""
return None

async def async_initialize(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions custom_components/xmrig/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"documentation": "https://github.com/hwmland/homeassistant-xmrig",
"issue_tracker": "https://github.com/hwmland/homeassistant-xmrig/issues",
"iot_class": "cloud_polling",
"after_dependencies": ["rest"],
"version": "0.1.0"
"after_dependencies": [],
"version": "0.2.0"
}
74 changes: 74 additions & 0 deletions custom_components/xmrig/restapicall.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""Support for REST API calls."""
import logging

import httpx

from homeassistant.helpers.httpx_client import get_async_client

DEFAULT_TIMEOUT = 30

_LOGGER = logging.getLogger(__name__)


class RestApiCall:
"""Class for handling the data retrieval."""

def __init__(
self,
hass,
method,
resource,
auth,
headers,
params,
data,
verify_ssl,
timeout=DEFAULT_TIMEOUT,
):
"""Initialize the data object."""
self._hass = hass
self._method = method
self._resource = resource
self._auth = auth
self._headers = headers
self._params = params
self._request_data = data
self._timeout = timeout
self._verify_ssl = verify_ssl
self._async_client = None
self.data = None
self.last_exception = None
self.headers = None
self.status = 0

async def async_update(self, log_errors=True):
"""Get the latest data from REST service with provided method."""
if not self._async_client:
self._async_client = get_async_client(
self._hass, verify_ssl=self._verify_ssl
)

_LOGGER.debug("Updating from %s", self._resource)
try:
response = await self._async_client.request(
self._method,
self._resource,
headers=self._headers,
params=self._params,
auth=self._auth,
data=self._request_data,
timeout=self._timeout,
follow_redirects=True,
)
self.data = response.text
self.headers = response.headers
self.status = response.status_code
except httpx.RequestError as ex:
if log_errors:
_LOGGER.error(
"Error fetching data: %s failed with %s", self._resource, ex
)
self.last_exception = ex
self.status = 500
self.data = None
self.headers = None
39 changes: 21 additions & 18 deletions custom_components/xmrig/strings.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
{
"config": {
"error": {
"name_exists": "Name already exists",
"instance_exists": "Instance already exists",
"invalid_answer": "Invalid answer from server"
},
"step": {
"user": {
"data": {
"name": "Name of the rig",
"address": "Instance address",
"token": "Access token"
},
"description": "XMRIG instance.",
"title": "XMRIG"
}
}
"config": {
"error": {
"name_exists": "Name already exists",
"address_exists": "You are already connected to this address",
"instance_exists": "Instance already exists",
"invalid_answer": "Invalid answer from server",
"no_answer": "No answer from the server. Check that server is running and you have correct address.",
"not_authorized": "You have no rights to access this server."
},
"step": {
"user": {
"data": {
"name": "Name of the rig",
"address": "Instance address",
"token": "Access token"
},
"description": "XMRIG instance.",
"title": "XMRIG"
}
}
}
}
}
5 changes: 2 additions & 3 deletions custom_components/xmrig/summary_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from typing import Any, Dict, Optional, List

from homeassistant import config_entries
from homeassistant.components.rest.data import RestData
from homeassistant.const import CONF_NAME
from homeassistant.core import callback
from homeassistant.core import HomeAssistant
Expand All @@ -35,11 +34,11 @@ def __init__(
super().__init__(DOMAIN, "summary", hass, config_entry)

def _vGetResource(self, config_entry: config_entries.ConfigEntry) -> str:
"""Get RestData resource"""
"""Get RestApiCall resource"""
return self._address + "/2/summary"

def _vGetHeaders(self, config_entry: config_entries.ConfigEntry) -> any: # @type
"""Get RestData headers"""
"""Get RestApiCall headers"""
if self._token is None:
return None
return {"Authorization": "Bearer " + self._token}
39 changes: 21 additions & 18 deletions custom_components/xmrig/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
{
"config": {
"error": {
"name_exists": "Name already exists",
"instance_exists": "Instance already exists",
"invalid_answer": "Invalid answer from server"
},
"step": {
"user": {
"data": {
"name": "Name of the rig",
"address": "Instance address",
"token": "Access token"
},
"description": "XMRIG instance.",
"title": "XMRIG"
}
}
"config": {
"error": {
"name_exists": "Name already exists",
"address_exists": "You are already connected to this address",
"instance_exists": "Instance already exists",
"invalid_answer": "Invalid answer from server",
"no_answer": "No answer from the server. Check that server is running and you have correct address.",
"not_authorized": "You have no rights to access this server."
},
"step": {
"user": {
"data": {
"name": "Name of the rig",
"address": "Instance address",
"token": "Access token"
},
"description": "XMRIG instance.",
"title": "XMRIG"
}
}
}
}
}
2 changes: 1 addition & 1 deletion hacs.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "XMRIG",
"name": "XMRIG integration",
"render_readme": true,
"iot_class": "cloud_polling"
}

0 comments on commit eedbced

Please sign in to comment.