core/homeassistant/components/sense/__init__.py

122 lines
3.9 KiB
Python

"""Support for monitoring a Sense energy sensor."""
from dataclasses import dataclass
from functools import partial
import logging
from sense_energy import (
ASyncSenseable,
SenseAuthenticationException,
SenseMFARequiredException,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_TIMEOUT, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (
ACTIVE_UPDATE_RATE,
SENSE_CONNECT_EXCEPTIONS,
SENSE_TIMEOUT_EXCEPTIONS,
SENSE_WEBSOCKET_EXCEPTIONS,
)
from .coordinator import SenseRealtimeCoordinator, SenseTrendCoordinator
_LOGGER = logging.getLogger(__name__)
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
type SenseConfigEntry = ConfigEntry[SenseData]
@dataclass(kw_only=True, slots=True)
class SenseData:
"""Sense data type."""
data: ASyncSenseable
trends: SenseTrendCoordinator
rt: SenseRealtimeCoordinator
async def async_setup_entry(hass: HomeAssistant, entry: SenseConfigEntry) -> bool:
"""Set up Sense from a config entry."""
entry_data = entry.data
timeout = entry_data[CONF_TIMEOUT]
access_token = entry_data.get("access_token", "")
user_id = entry_data.get("user_id", "")
device_id = entry_data.get("device_id", "")
refresh_token = entry_data.get("refresh_token", "")
monitor_id = entry_data.get("monitor_id", "")
client_session = async_get_clientsession(hass)
# Creating the AsyncSenseable object loads
# ssl certificates which does blocking IO
gateway = await hass.async_add_executor_job(
partial(
ASyncSenseable,
api_timeout=timeout,
wss_timeout=timeout,
client_session=client_session,
)
)
gateway.rate_limit = ACTIVE_UPDATE_RATE
try:
gateway.load_auth(access_token, user_id, device_id, refresh_token)
gateway.set_monitor_id(monitor_id)
await gateway.get_monitor_data()
except (SenseAuthenticationException, SenseMFARequiredException) as err:
_LOGGER.warning("Sense authentication expired")
raise ConfigEntryAuthFailed(err) from err
except SENSE_TIMEOUT_EXCEPTIONS as err:
raise ConfigEntryNotReady(
str(err) or "Timed out during authentication"
) from err
except SENSE_CONNECT_EXCEPTIONS as err:
raise ConfigEntryNotReady(str(err)) from err
try:
await gateway.fetch_devices()
await gateway.update_realtime()
except SENSE_TIMEOUT_EXCEPTIONS as err:
raise ConfigEntryNotReady(
str(err) or "Timed out during realtime update"
) from err
except SENSE_WEBSOCKET_EXCEPTIONS as err:
raise ConfigEntryNotReady(str(err) or "Error during realtime update") from err
trends_coordinator = SenseTrendCoordinator(hass, gateway)
realtime_coordinator = SenseRealtimeCoordinator(hass, gateway)
# This can take longer than 60s and we already know
# sense is online since get_discovered_device_data was
# successful so we do it later.
entry.async_create_background_task(
hass,
trends_coordinator.async_request_refresh(),
"sense.trends-coordinator-refresh",
)
entry.async_create_background_task(
hass,
realtime_coordinator.async_request_refresh(),
"sense.realtime-coordinator-refresh",
)
entry.runtime_data = SenseData(
data=gateway,
trends=trends_coordinator,
rt=realtime_coordinator,
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: SenseConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)