* Remove unnecessary exception re-wraps * Preserve exception chains on re-raise We slap "from cause" to almost all possible cases here. In some cases it could conceivably be better to do "from None" if we really want to hide the cause. However those should be in the minority, and "from cause" should be an improvement over the corresponding raise without a "from" in all cases anyway. The only case where we raise from None here is in plex, where the exception for an original invalid SSL cert is not the root cause for failure to validate a newly fetched one. Follow local convention on exception variable names if there is a consistent one, otherwise `err` to match with majority of codebase. * Fix mistaken re-wrap in homematicip_cloud/hap.py Missed the difference between HmipConnectionError and HmipcConnectionError. * Do not hide original error on plex new cert validation error Original is not the cause for the new one, but showing old in the traceback is useful nevertheless.
174 lines
5.4 KiB
Python
174 lines
5.4 KiB
Python
"""The Glances component."""
|
|
from datetime import timedelta
|
|
import logging
|
|
|
|
from glances_api import Glances, exceptions
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.config_entries import SOURCE_IMPORT
|
|
from homeassistant.const import (
|
|
CONF_HOST,
|
|
CONF_NAME,
|
|
CONF_PASSWORD,
|
|
CONF_PORT,
|
|
CONF_SCAN_INTERVAL,
|
|
CONF_SSL,
|
|
CONF_USERNAME,
|
|
CONF_VERIFY_SSL,
|
|
)
|
|
from homeassistant.core import Config, HomeAssistant
|
|
from homeassistant.exceptions import ConfigEntryNotReady
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|
import homeassistant.helpers.config_validation as cv
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
|
from homeassistant.helpers.event import async_track_time_interval
|
|
|
|
from .const import (
|
|
CONF_VERSION,
|
|
DATA_UPDATED,
|
|
DEFAULT_HOST,
|
|
DEFAULT_NAME,
|
|
DEFAULT_PORT,
|
|
DEFAULT_SCAN_INTERVAL,
|
|
DEFAULT_VERSION,
|
|
DOMAIN,
|
|
)
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
GLANCES_SCHEMA = vol.All(
|
|
vol.Schema(
|
|
{
|
|
vol.Required(CONF_HOST, default=DEFAULT_HOST): cv.string,
|
|
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
vol.Optional(CONF_USERNAME): cv.string,
|
|
vol.Optional(CONF_PASSWORD): cv.string,
|
|
vol.Optional(CONF_SSL, default=False): cv.boolean,
|
|
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
|
|
vol.Optional(CONF_VERSION, default=DEFAULT_VERSION): vol.In([2, 3]),
|
|
}
|
|
)
|
|
)
|
|
|
|
CONFIG_SCHEMA = vol.Schema(
|
|
{DOMAIN: vol.All(cv.ensure_list, [GLANCES_SCHEMA])}, extra=vol.ALLOW_EXTRA
|
|
)
|
|
|
|
|
|
async def async_setup(hass: HomeAssistant, config: Config) -> bool:
|
|
"""Configure Glances using config flow only."""
|
|
if DOMAIN in config:
|
|
for entry in config[DOMAIN]:
|
|
hass.async_create_task(
|
|
hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": SOURCE_IMPORT}, data=entry
|
|
)
|
|
)
|
|
|
|
return True
|
|
|
|
|
|
async def async_setup_entry(hass, config_entry):
|
|
"""Set up Glances from config entry."""
|
|
client = GlancesData(hass, config_entry)
|
|
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = client
|
|
if not await client.async_setup():
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
async def async_unload_entry(hass, config_entry):
|
|
"""Unload a config entry."""
|
|
await hass.config_entries.async_forward_entry_unload(config_entry, "sensor")
|
|
hass.data[DOMAIN].pop(config_entry.entry_id)
|
|
return True
|
|
|
|
|
|
class GlancesData:
|
|
"""Get the latest data from Glances api."""
|
|
|
|
def __init__(self, hass, config_entry):
|
|
"""Initialize the Glances data."""
|
|
self.hass = hass
|
|
self.config_entry = config_entry
|
|
self.api = None
|
|
self.unsub_timer = None
|
|
self.available = False
|
|
|
|
@property
|
|
def host(self):
|
|
"""Return client host."""
|
|
return self.config_entry.data[CONF_HOST]
|
|
|
|
async def async_update(self):
|
|
"""Get the latest data from the Glances REST API."""
|
|
try:
|
|
await self.api.get_data()
|
|
self.available = True
|
|
except exceptions.GlancesApiError:
|
|
_LOGGER.error("Unable to fetch data from Glances")
|
|
self.available = False
|
|
_LOGGER.debug("Glances data updated")
|
|
async_dispatcher_send(self.hass, DATA_UPDATED)
|
|
|
|
async def async_setup(self):
|
|
"""Set up the Glances client."""
|
|
try:
|
|
self.api = get_api(self.hass, self.config_entry.data)
|
|
await self.api.get_data()
|
|
self.available = True
|
|
_LOGGER.debug("Successfully connected to Glances")
|
|
|
|
except exceptions.GlancesApiConnectionError as err:
|
|
_LOGGER.debug("Can not connect to Glances")
|
|
raise ConfigEntryNotReady from err
|
|
|
|
self.add_options()
|
|
self.set_scan_interval(self.config_entry.options[CONF_SCAN_INTERVAL])
|
|
self.config_entry.add_update_listener(self.async_options_updated)
|
|
|
|
self.hass.async_create_task(
|
|
self.hass.config_entries.async_forward_entry_setup(
|
|
self.config_entry, "sensor"
|
|
)
|
|
)
|
|
return True
|
|
|
|
def add_options(self):
|
|
"""Add options for Glances integration."""
|
|
if not self.config_entry.options:
|
|
options = {CONF_SCAN_INTERVAL: DEFAULT_SCAN_INTERVAL}
|
|
self.hass.config_entries.async_update_entry(
|
|
self.config_entry, options=options
|
|
)
|
|
|
|
def set_scan_interval(self, scan_interval):
|
|
"""Update scan interval."""
|
|
|
|
async def refresh(event_time):
|
|
"""Get the latest data from Glances api."""
|
|
await self.async_update()
|
|
|
|
if self.unsub_timer is not None:
|
|
self.unsub_timer()
|
|
self.unsub_timer = async_track_time_interval(
|
|
self.hass, refresh, timedelta(seconds=scan_interval)
|
|
)
|
|
|
|
@staticmethod
|
|
async def async_options_updated(hass, entry):
|
|
"""Triggered by config entry options updates."""
|
|
hass.data[DOMAIN][entry.entry_id].set_scan_interval(
|
|
entry.options[CONF_SCAN_INTERVAL]
|
|
)
|
|
|
|
|
|
def get_api(hass, entry):
|
|
"""Return the api from glances_api."""
|
|
params = entry.copy()
|
|
params.pop(CONF_NAME)
|
|
verify_ssl = params.pop(CONF_VERIFY_SSL)
|
|
session = async_get_clientsession(hass, verify_ssl)
|
|
return Glances(hass.loop, session, **params)
|