"""Support for Vera devices.""" import asyncio from collections import defaultdict import logging import pyvera as veraApi from requests.exceptions import RequestException from homeassistant.const import ( CONF_EXCLUDE, CONF_LIGHTS, EVENT_HOMEASSISTANT_STOP, Platform, ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from .common import ( ControllerData, SubscriptionRegistry, VeraConfigEntry, get_configured_platforms, ) from .config_flow import fix_device_id_list, new_options from .const import CONF_CONTROLLER, DOMAIN _LOGGER = logging.getLogger(__name__) CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False) async def async_setup_entry(hass: HomeAssistant, entry: VeraConfigEntry) -> bool: """Do setup of vera.""" # Use options entered during initial config flow or provided from configuration.yml if entry.data.get(CONF_LIGHTS) or entry.data.get(CONF_EXCLUDE): hass.config_entries.async_update_entry( entry=entry, data=entry.data, options=new_options( entry.data.get(CONF_LIGHTS, []), entry.data.get(CONF_EXCLUDE, []), ), ) saved_light_ids = entry.options.get(CONF_LIGHTS, []) saved_exclude_ids = entry.options.get(CONF_EXCLUDE, []) base_url = entry.data[CONF_CONTROLLER] light_ids = fix_device_id_list(saved_light_ids) exclude_ids = fix_device_id_list(saved_exclude_ids) # If the ids were corrected. Update the config entry. if light_ids != saved_light_ids or exclude_ids != saved_exclude_ids: hass.config_entries.async_update_entry( entry=entry, options=new_options(light_ids, exclude_ids) ) # Initialize the Vera controller. subscription_registry = SubscriptionRegistry(hass) controller = veraApi.VeraController(base_url, subscription_registry) try: def _get_devices_and_scenes(): """Get devices and scenes from the Vera controller.""" return controller.get_devices(), controller.get_scenes() all_devices, all_scenes = await hass.async_add_executor_job( _get_devices_and_scenes ) except RequestException as exception: # There was a network related error connecting to the Vera controller. _LOGGER.exception("Error communicating with Vera API") raise ConfigEntryNotReady from exception # Exclude devices unwanted by user. devices = [device for device in all_devices if device.device_id not in exclude_ids] vera_devices: defaultdict[Platform, list[veraApi.VeraDevice]] = defaultdict(list) for device in devices: device_type = map_vera_device(device, light_ids) if device_type is not None: vera_devices[device_type].append(device) controller_data = ControllerData( controller=controller, devices=vera_devices, scenes=all_scenes, config_entry=entry, ) entry.runtime_data = controller_data # Forward the config data to the necessary platforms. await hass.config_entries.async_forward_entry_setups( entry, platforms=get_configured_platforms(controller_data) ) def stop_subscription(event): """Stop SubscriptionRegistry updates.""" controller.stop() await hass.async_add_executor_job(controller.start) entry.async_on_unload( hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_subscription) ) return True async def async_unload_entry( hass: HomeAssistant, config_entry: VeraConfigEntry ) -> bool: """Unload vera config entry.""" controller_data = config_entry.runtime_data await asyncio.gather( *( hass.config_entries.async_unload_platforms( config_entry, get_configured_platforms(controller_data) ), hass.async_add_executor_job(controller_data.controller.stop), ) ) return True def map_vera_device( vera_device: veraApi.VeraDevice, remap: list[int] ) -> Platform | None: """Map vera classes to Home Assistant types.""" type_map = { veraApi.VeraDimmer: Platform.LIGHT, veraApi.VeraBinarySensor: Platform.BINARY_SENSOR, veraApi.VeraSensor: Platform.SENSOR, veraApi.VeraArmableDevice: Platform.SWITCH, veraApi.VeraLock: Platform.LOCK, veraApi.VeraThermostat: Platform.CLIMATE, veraApi.VeraCurtain: Platform.COVER, veraApi.VeraSceneController: Platform.SENSOR, veraApi.VeraSwitch: Platform.SWITCH, } def map_special_case(instance_class: type, entity_type: Platform) -> Platform: if instance_class is veraApi.VeraSwitch and vera_device.device_id in remap: return Platform.LIGHT return entity_type return next( iter( map_special_case(instance_class, entity_type) for instance_class, entity_type in type_map.items() if isinstance(vera_device, instance_class) ), None, )