"""Support for SimpliSafe alarm systems.""" import asyncio import logging from datetime import timedelta import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import ( CONF_CODE, CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_USERNAME) from homeassistant.core import callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers import config_validation as cv from .config_flow import configured_instances from .const import DATA_CLIENT, DEFAULT_SCAN_INTERVAL, DOMAIN, TOPIC_UPDATE _LOGGER = logging.getLogger(__name__) CONF_ACCOUNTS = 'accounts' DATA_LISTENER = 'listener' ACCOUNT_CONFIG_SCHEMA = vol.Schema({ vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_CODE): cv.string, vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): cv.time_period, }) CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Optional(CONF_ACCOUNTS): vol.All(cv.ensure_list, [ACCOUNT_CONFIG_SCHEMA]), }), }, extra=vol.ALLOW_EXTRA) @callback def _async_save_refresh_token(hass, config_entry, token): hass.config_entries.async_update_entry( config_entry, data={ **config_entry.data, CONF_TOKEN: token }) async def async_setup(hass, config): """Set up the SimpliSafe component.""" hass.data[DOMAIN] = {} hass.data[DOMAIN][DATA_CLIENT] = {} hass.data[DOMAIN][DATA_LISTENER] = {} if DOMAIN not in config: return True conf = config[DOMAIN] for account in conf[CONF_ACCOUNTS]: if account[CONF_USERNAME] in configured_instances(hass): continue hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, context={'source': SOURCE_IMPORT}, data={ CONF_USERNAME: account[CONF_USERNAME], CONF_PASSWORD: account[CONF_PASSWORD], CONF_CODE: account.get(CONF_CODE), CONF_SCAN_INTERVAL: account[CONF_SCAN_INTERVAL], })) return True async def async_setup_entry(hass, config_entry): """Set up SimpliSafe as config entry.""" from simplipy import API from simplipy.errors import InvalidCredentialsError, SimplipyError websession = aiohttp_client.async_get_clientsession(hass) try: simplisafe = await API.login_via_token( config_entry.data[CONF_TOKEN], websession) except InvalidCredentialsError: _LOGGER.error('Invalid credentials provided') return False except SimplipyError as err: _LOGGER.error('Config entry failed: %s', err) raise ConfigEntryNotReady _async_save_refresh_token(hass, config_entry, simplisafe.refresh_token) systems = await simplisafe.get_systems() hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = systems hass.async_create_task( hass.config_entries.async_forward_entry_setup( config_entry, 'alarm_control_panel')) async def refresh(event_time): """Refresh data from the SimpliSafe account.""" tasks = [system.update() for system in systems] results = await asyncio.gather(*tasks, return_exceptions=True) for system, result in zip(systems, results): if isinstance(result, SimplipyError): _LOGGER.error( 'There was error updating "%s": %s', system.address, result) continue _LOGGER.debug('Updated status of "%s"', system.address) async_dispatcher_send( hass, TOPIC_UPDATE.format(system.system_id)) if system.api.refresh_token_dirty: _async_save_refresh_token( hass, config_entry, system.api.refresh_token) hass.data[DOMAIN][DATA_LISTENER][ config_entry.entry_id] = async_track_time_interval( hass, refresh, timedelta(seconds=config_entry.data[CONF_SCAN_INTERVAL])) return True async def async_unload_entry(hass, entry): """Unload a SimpliSafe config entry.""" await hass.config_entries.async_forward_entry_unload( entry, 'alarm_control_panel') hass.data[DOMAIN][DATA_CLIENT].pop(entry.entry_id) remove_listener = hass.data[DOMAIN][DATA_LISTENER].pop(entry.entry_id) remove_listener() return True