core/homeassistant/components/alexa/config.py

159 lines
4.5 KiB
Python
Raw Normal View History

"""Config helpers for Alexa."""
from abc import ABC, abstractmethod
import logging
from homeassistant.core import callback
from homeassistant.helpers.storage import Store
from .const import DOMAIN
from .state_report import async_enable_proactive_mode
STORE_AUTHORIZED = "authorized"
_LOGGER = logging.getLogger(__name__)
class AbstractConfig(ABC):
"""Hold the configuration for Alexa."""
_unsub_proactive_report = None
def __init__(self, hass):
"""Initialize abstract config."""
self.hass = hass
self._store = None
async def async_initialize(self):
"""Perform async initialization of config."""
self._store = AlexaConfigStore(self.hass)
await self._store.async_load()
@property
def supports_auth(self):
"""Return if config supports auth."""
return False
@property
def should_report_state(self):
"""Return if states should be proactively reported."""
return False
@property
def endpoint(self):
"""Endpoint for report state."""
return None
@property
@abstractmethod
def locale(self):
"""Return config locale."""
@property
def entity_config(self):
"""Return entity config."""
return {}
@property
def is_reporting_states(self):
"""Return if proactive mode is enabled."""
return self._unsub_proactive_report is not None
@callback
@abstractmethod
def user_identifier(self):
"""Return an identifier for the user that represents this config."""
async def async_enable_proactive_mode(self):
"""Enable proactive mode."""
if self._unsub_proactive_report is None:
self._unsub_proactive_report = self.hass.async_create_task(
async_enable_proactive_mode(self.hass, self)
)
2019-06-25 05:04:31 +00:00
try:
await self._unsub_proactive_report
except Exception:
self._unsub_proactive_report = None
2019-06-25 05:04:31 +00:00
raise
async def async_disable_proactive_mode(self):
"""Disable proactive mode."""
2021-10-30 14:32:41 +00:00
if unsub_func := await self._unsub_proactive_report:
unsub_func()
self._unsub_proactive_report = None
@callback
def should_expose(self, entity_id):
"""If an entity should be exposed."""
# pylint: disable=no-self-use
return False
@callback
def async_invalidate_access_token(self):
"""Invalidate access token."""
raise NotImplementedError
async def async_get_access_token(self):
"""Get an access token."""
raise NotImplementedError
async def async_accept_grant(self, code):
"""Accept a grant."""
raise NotImplementedError
@property
def authorized(self):
"""Return authorization status."""
return self._store.authorized
async def set_authorized(self, authorized):
"""Set authorization status.
- Set when an incoming message is received from Alexa.
- Unset if state reporting fails
"""
self._store.set_authorized(authorized)
if self.should_report_state != self.is_reporting_states:
if self.should_report_state:
_LOGGER.debug("Enable proactive mode")
try:
await self.async_enable_proactive_mode()
except Exception:
# We failed to enable proactive mode, unset authorized flag
self._store.set_authorized(False)
raise
else:
_LOGGER.debug("Disable proactive mode")
await self.async_disable_proactive_mode()
class AlexaConfigStore:
"""A configuration store for Alexa."""
_STORAGE_VERSION = 1
_STORAGE_KEY = DOMAIN
def __init__(self, hass):
"""Initialize a configuration store."""
self._data = None
self._hass = hass
self._store = Store(hass, self._STORAGE_VERSION, self._STORAGE_KEY)
@property
def authorized(self):
"""Return authorization status."""
return self._data[STORE_AUTHORIZED]
@callback
def set_authorized(self, authorized):
"""Set authorization status."""
if authorized != self._data[STORE_AUTHORIZED]:
self._data[STORE_AUTHORIZED] = authorized
self._store.async_delay_save(lambda: self._data, 1.0)
async def async_load(self):
"""Load saved configuration from disk."""
if data := await self._store.async_load():
self._data = data
else:
self._data = {STORE_AUTHORIZED: False}