Esempio n. 1
0
async def async_migrate_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Handle migration of a previous version config entry.

    A config entry created under a previous version must go through the
    integration setup again so we can properly retrieve the needed data
    elements. Force this by removing the entry and triggering a new flow.
    """
    from pysmartthings import SmartThings

    # Remove the installed_app, which if already removed raises a 403 error.
    api = SmartThings(async_get_clientsession(hass),
                      entry.data[CONF_ACCESS_TOKEN])
    installed_app_id = entry.data[CONF_INSTALLED_APP_ID]
    try:
        await api.delete_installed_app(installed_app_id)
    except ClientResponseError as ex:
        if ex.status == 403:
            _LOGGER.exception("Installed app %s has already been removed",
                              installed_app_id)
        else:
            raise
    _LOGGER.debug("Removed installed app %s", installed_app_id)

    # Delete the entry
    hass.async_create_task(
        hass.config_entries.async_remove(entry.entry_id))
    # only create new flow if there isn't a pending one for SmartThings.
    flows = hass.config_entries.flow.async_progress()
    if not [flow for flow in flows if flow['handler'] == DOMAIN]:
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN, context={'source': 'import'}))

    # Return False because it could not be migrated.
    return False
Esempio n. 2
0
def async_publish(hass: HomeAssistantType, topic: Any, payload, qos=None,
                  retain=None) -> None:
    """Publish message to an MQTT topic."""
    data = _build_publish_data(topic, qos, retain)
    data[ATTR_PAYLOAD] = payload
    hass.async_create_task(
        hass.services.async_call(DOMAIN, SERVICE_PUBLISH, data))
Esempio n. 3
0
async def async_setup_entry(hass: HomeAssistantType,
                            entry: ConfigType) -> bool:
    """Set up Toon from a config entry."""
    from toonapilib import Toon

    conf = hass.data.get(DATA_TOON_CONFIG)

    toon = await hass.async_add_executor_job(partial(
        Toon, entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD],
        conf[CONF_CLIENT_ID], conf[CONF_CLIENT_SECRET],
        tenant_id=entry.data[CONF_TENANT],
        display_common_name=entry.data[CONF_DISPLAY]))

    hass.data.setdefault(DATA_TOON_CLIENT, {})[entry.entry_id] = toon

    # Register device for the Meter Adapter, since it will have no entities.
    device_registry = await dr.async_get_registry(hass)
    device_registry.async_get_or_create(
        config_entry_id=entry.entry_id,
        identifiers={
            (DOMAIN, toon.agreement.id, 'meter_adapter'),
        },
        manufacturer='Eneco',
        name="Meter Adapter",
        via_hub=(DOMAIN, toon.agreement.id)
    )

    for component in 'binary_sensor', 'climate', 'sensor':
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Esempio n. 4
0
def async_setup_scanner_platform(hass: HomeAssistantType, config: ConfigType,
                                 scanner: Any, async_see_device: Callable,
                                 platform: str):
    """Set up the connect scanner-based platform to device tracker.

    This method must be run in the event loop.
    """
    interval = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
    update_lock = asyncio.Lock(loop=hass.loop)
    scanner.hass = hass

    # Initial scan of each mac we also tell about host name for config
    seen = set()  # type: Any

    async def async_device_tracker_scan(now: dt_util.dt.datetime):
        """Handle interval matches."""
        if update_lock.locked():
            _LOGGER.warning(
                "Updating device list from %s took longer than the scheduled "
                "scan interval %s", platform, interval)
            return

        async with update_lock:
            found_devices = await scanner.async_scan_devices()

        for mac in found_devices:
            if mac in seen:
                host_name = None
            else:
                host_name = await scanner.async_get_device_name(mac)
                seen.add(mac)

            try:
                extra_attributes = \
                    await scanner.async_get_extra_attributes(mac)
            except NotImplementedError:
                extra_attributes = dict()

            kwargs = {
                'mac': mac,
                'host_name': host_name,
                'source_type': SOURCE_TYPE_ROUTER,
                'attributes': {
                    'scanner': scanner.__class__.__name__,
                    **extra_attributes
                }
            }

            zone_home = hass.states.get(zone.ENTITY_ID_HOME)
            if zone_home:
                kwargs['gps'] = [zone_home.attributes[ATTR_LATITUDE],
                                 zone_home.attributes[ATTR_LONGITUDE]]
                kwargs['gps_accuracy'] = 0

            hass.async_create_task(async_see_device(**kwargs))

    async_track_time_interval(hass, async_device_tracker_scan, interval)
    hass.async_create_task(async_device_tracker_scan(None))
Esempio n. 5
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Initialize config entry which represents the HEOS controller."""
    from pyheos import Heos, CommandError
    host = entry.data[CONF_HOST]
    # Setting all_progress_events=False ensures that we only receive a
    # media position update upon start of playback or when media changes
    controller = Heos(host, all_progress_events=False)
    try:
        await controller.connect(auto_reconnect=True)
    # Auto reconnect only operates if initial connection was successful.
    except (asyncio.TimeoutError, ConnectionError, CommandError) as error:
        await controller.disconnect()
        _LOGGER.debug("Unable to connect to controller %s: %s", host, error)
        raise ConfigEntryNotReady

    # Disconnect when shutting down
    async def disconnect_controller(event):
        await controller.disconnect()
    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, disconnect_controller)

    # Get players and sources
    try:
        players = await controller.get_players()
        favorites = {}
        if controller.is_signed_in:
            favorites = await controller.get_favorites()
        else:
            _LOGGER.warning(
                "%s is not logged in to a HEOS account and will be unable "
                "to retrieve HEOS favorites: Use the 'heos.sign_in' service "
                "to sign-in to a HEOS account", host)
        inputs = await controller.get_input_sources()
    except (asyncio.TimeoutError, ConnectionError, CommandError) as error:
        await controller.disconnect()
        _LOGGER.debug("Unable to retrieve players and sources: %s", error,
                      exc_info=isinstance(error, CommandError))
        raise ConfigEntryNotReady

    controller_manager = ControllerManager(hass, controller)
    await controller_manager.connect_listeners()

    source_manager = SourceManager(favorites, inputs)
    source_manager.connect_update(hass, controller)

    hass.data[DOMAIN] = {
        DATA_CONTROLLER_MANAGER: controller_manager,
        DATA_SOURCE_MANAGER: source_manager,
        MEDIA_PLAYER_DOMAIN: players
    }

    services.register(hass, controller)

    hass.async_create_task(hass.config_entries.async_forward_entry_setup(
        entry, MEDIA_PLAYER_DOMAIN))
    return True
Esempio n. 6
0
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
    """Start the MQTT protocol service."""
    conf = config.get(DOMAIN)  # type: Optional[ConfigType]

    # We need this because discovery can cause components to be set up and
    # otherwise it will not load the users config.
    # This needs a better solution.
    hass.data[DATA_MQTT_HASS_CONFIG] = config

    if conf is None:
        # If we have a config entry, setup is done by that config entry.
        # If there is no config entry, this should fail.
        return bool(hass.config_entries.async_entries(DOMAIN))

    conf = dict(conf)

    if CONF_EMBEDDED in conf or CONF_BROKER not in conf:
        if (conf.get(CONF_PASSWORD) is None and
                config.get('http', {}).get('api_password') is not None):
            _LOGGER.error(
                "Starting from release 0.76, the embedded MQTT broker does not"
                " use api_password as default password anymore. Please set"
                " password configuration. See https://home-assistant.io/docs/"
                "mqtt/broker#embedded-broker for details")
            return False

        broker_config = await _async_setup_server(hass, config)

        if broker_config is None:
            _LOGGER.error("Unable to start embedded MQTT broker")
            return False

        conf.update({
            CONF_BROKER: broker_config[0],
            CONF_PORT: broker_config[1],
            CONF_USERNAME: broker_config[2],
            CONF_PASSWORD: broker_config[3],
            CONF_CERTIFICATE: broker_config[4],
            CONF_PROTOCOL: broker_config[5],
            CONF_CLIENT_KEY: None,
            CONF_CLIENT_CERT: None,
            CONF_TLS_INSECURE: None,
        })

    hass.data[DATA_MQTT_CONFIG] = conf

    # Only import if we haven't before.
    if not hass.config_entries.async_entries(DOMAIN):
        hass.async_create_task(hass.config_entries.flow.async_init(
            DOMAIN, context={'source': config_entries.SOURCE_IMPORT},
            data={}
        ))

    return True
Esempio n. 7
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Establish connection with Daikin."""
    conf = entry.data
    daikin_api = await daikin_api_setup(hass, conf[CONF_HOST])
    if not daikin_api:
        return False
    hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: daikin_api})
    for component in COMPONENT_TYPES:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(
                entry, component))
    return True
Esempio n. 8
0
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
    """Start the MQTT protocol service."""
    conf = config.get(DOMAIN)  # type: Optional[ConfigType]

    # We need this because discovery can cause components to be set up and
    # otherwise it will not load the users config.
    # This needs a better solution.
    hass.data[DATA_MQTT_HASS_CONFIG] = config

    websocket_api.async_register_command(hass, websocket_subscribe)

    if conf is None:
        # If we have a config entry, setup is done by that config entry.
        # If there is no config entry, this should fail.
        return bool(hass.config_entries.async_entries(DOMAIN))

    conf = dict(conf)

    if CONF_EMBEDDED in conf or CONF_BROKER not in conf:

        broker_config = await _async_setup_server(hass, config)

        if broker_config is None:
            _LOGGER.error("Unable to start embedded MQTT broker")
            return False

        conf.update({
            CONF_BROKER: broker_config[0],
            CONF_PORT: broker_config[1],
            CONF_USERNAME: broker_config[2],
            CONF_PASSWORD: broker_config[3],
            CONF_CERTIFICATE: broker_config[4],
            CONF_PROTOCOL: broker_config[5],
            CONF_CLIENT_KEY: None,
            CONF_CLIENT_CERT: None,
            CONF_TLS_INSECURE: None,
        })

    hass.data[DATA_MQTT_CONFIG] = conf

    # Only import if we haven't before.
    if not hass.config_entries.async_entries(DOMAIN):
        hass.async_create_task(hass.config_entries.flow.async_init(
            DOMAIN, context={'source': config_entries.SOURCE_IMPORT},
            data={}
        ))

    return True
Esempio n. 9
0
async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up UPnP component."""
    conf_default = CONFIG_SCHEMA({DOMAIN: {}})[DOMAIN]
    conf = config.get(DOMAIN, conf_default)
    local_ip = await hass.async_add_executor_job(get_local_ip)
    hass.data[DOMAIN] = {
        'config': conf,
        'devices': {},
        'local_ip': config.get(CONF_LOCAL_IP, local_ip),
        'ports': conf.get('ports', {}),
    }

    if conf is not None:
        hass.async_create_task(hass.config_entries.flow.async_init(
            DOMAIN, context={'source': config_entries.SOURCE_IMPORT}))

    return True
Esempio n. 10
0
async def async_setup_entry(hass: HomeAssistantType,
                            config_entry: ConfigEntry):
    """Set up UPnP/IGD-device from a config entry."""
    await async_ensure_domain_data(hass)
    data = config_entry.data

    # build UPnP/IGD device
    ssdp_description = data[CONF_SSDP_DESCRIPTION]
    try:
        device = await Device.async_create_device(hass, ssdp_description)
    except (asyncio.TimeoutError, aiohttp.ClientError):
        _LOGGER.error('Unable to create upnp-device')
        return False

    hass.data[DOMAIN]['devices'][device.udn] = device

    # port mapping
    if data.get(CONF_ENABLE_PORT_MAPPING):
        local_ip = hass.data[DOMAIN]['local_ip']
        ports = hass.data[DOMAIN]['auto_config']['ports']
        _LOGGER.debug('Enabling port mappings: %s', ports)

        hass_port = None
        if hasattr(hass, 'http'):
            hass_port = hass.http.server_port
        ports = _substitute_hass_ports(ports, hass_port=hass_port)
        await device.async_add_port_mappings(ports, local_ip)

    # sensors
    if data.get(CONF_ENABLE_SENSORS):
        _LOGGER.debug('Enabling sensors')

        # register sensor setup handlers
        hass.async_create_task(hass.config_entries.async_forward_entry_setup(
            config_entry, 'sensor'))

    async def delete_port_mapping(event):
        """Delete port mapping on quit."""
        if data.get(CONF_ENABLE_PORT_MAPPING):
            _LOGGER.debug('Deleting port mappings')
            await device.async_delete_port_mappings()
    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, delete_port_mapping)

    return True
Esempio n. 11
0
async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up the HEOS component."""
    if DOMAIN not in config:
        return True
    host = config[DOMAIN][CONF_HOST]
    entries = hass.config_entries.async_entries(DOMAIN)
    if not entries:
        # Create new entry based on config
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN, context={'source': 'import'},
                data={CONF_HOST: host}))
    else:
        # Check if host needs to be updated
        entry = entries[0]
        if entry.data[CONF_HOST] != host:
            entry.data[CONF_HOST] = host
            entry.title = format_title(host)
            hass.config_entries.async_update_entry(entry)

    return True
Esempio n. 12
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
    """Set up the esphome component."""
    hass.data.setdefault(DATA_COMPENSATION, {})

    if entry.unique_id == CONF_MQTT_PREFIX:
        _LOGGER.warning("Skipping %s.", CONF_MQTT_PREFIX)
        return False

    datapoints = entry.options.get(CONF_DATAPOINTS, [(1,1), (2,2)])

    hass_data = calculate_poly(entry.data, datapoints)

    ## Registers update listener to update config entry when options are updated.
    ## Store a reference to the unsubscribe function to cleanup if an entry is unloaded.
    unsub_options_update_listener = entry.add_update_listener(options_update_listener)
    hass.data[DATA_COMPENSATION][entry.unique_id] = hass_data
    hass.data[DATA_COMPENSATION][entry.unique_id]["unsub_options_update_listener"] = unsub_options_update_listener

    hass.async_create_task(
        hass.config_entries.async_forward_entry_setup(entry, "sensor")
    )
    return True
Esempio n. 13
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Load the saved entities."""
    host = entry.data[CONF_HOST]
    port = entry.data[CONF_PORT]

    coordinator = CertExpiryDataUpdateCoordinator(hass, entry)
    await coordinator.async_set_options()
    await coordinator.async_refresh()

    if not coordinator.last_update_success:
        raise ConfigEntryNotReady

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.entry_id] = coordinator

    if entry.unique_id is None:
        hass.config_entries.async_update_entry(entry, unique_id=f"{host}:{port}")

    hass.async_create_task(
        hass.config_entries.async_forward_entry_setup(entry, "sensor")
    )
    return True
Esempio n. 14
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Set up Somfy from a config entry."""
    # Backwards compat
    if "auth_implementation" not in entry.data:
        hass.config_entries.async_update_entry(
            entry, data={
                **entry.data, "auth_implementation": DOMAIN
            })

    implementation = await config_entry_oauth2_flow.async_get_config_entry_implementation(
        hass, entry)

    hass.data[DOMAIN][API] = api.ConfigEntrySomfyApi(hass, entry,
                                                     implementation)

    await update_all_devices(hass)

    for component in SOMFY_COMPONENTS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Esempio n. 15
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Set up Synology DSM sensors."""
    host = entry.data[CONF_HOST]
    port = entry.data[CONF_PORT]
    username = entry.data[CONF_USERNAME]
    password = entry.data[CONF_PASSWORD]
    unit = hass.config.units.temperature_unit
    use_ssl = entry.data[CONF_SSL]
    device_token = entry.data.get("device_token")

    api = SynoApi(hass, host, port, username, password, unit, use_ssl,
                  device_token)

    await api.async_setup()

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.unique_id] = api

    hass.async_create_task(
        hass.config_entries.async_forward_entry_setup(entry, "sensor"))

    return True
Esempio n. 16
0
async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up the component."""
    hass.data[DOMAIN_DATA_ENTRIES] = {}
    hass.data[DOMAIN_DATA_CONFIG] = {}

    for device in config[DOMAIN]:
        hass.data[DOMAIN_DATA_CONFIG][
            (device[CONF_HOST], device[CONF_PORT])
        ] = device

        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN,
                context={"source": config_entries.SOURCE_IMPORT},
                data={
                    CONF_HOST: device[CONF_HOST],
                    CONF_PORT: device[CONF_PORT],
                },
            )
        )

    return True
Esempio n. 17
0
async def platform_async_setup_entry(
    hass: HomeAssistantType,
    config_entry: ConfigEntry,
    async_add_entities,
    *,
    component_key: str,
    info_type,
    entity_type,
    state_type,
) -> bool:
    """Set up this integration using UI."""
    if config_entry.source == config_entries.SOURCE_IMPORT:
        # We get here if the integration is set up using YAML
        hass.async_create_task(
            hass.config_entries.async_remove(config_entry.entry_id))
        return False
    # Print startup message
    config_entry.options = config_entry.data
    config_entry.add_update_listener(update_listener)
    # Add sensor
    return await hass.config_entries.async_forward_entry_setup(
        config_entry, PLATFORM)
Esempio n. 18
0
async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up UPnP component."""
    _LOGGER.debug("async_setup, config: %s", config)
    conf_default = CONFIG_SCHEMA({DOMAIN: {}})[DOMAIN]
    conf = config.get(DOMAIN, conf_default)
    local_ip = await hass.async_add_executor_job(get_local_ip)
    hass.data[DOMAIN] = {
        DOMAIN_CONFIG: conf,
        DOMAIN_COORDINATORS: {},
        DOMAIN_DEVICES: {},
        DOMAIN_LOCAL_IP: conf.get(CONF_LOCAL_IP, local_ip),
    }

    # Only start if set up via configuration.yaml.
    if DOMAIN in config:
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN, context={"source": config_entries.SOURCE_IMPORT}
            )
        )

    return True
Esempio n. 19
0
async def async_setup(hass: HomeAssistantType, config: ConfigEntry):
    """Set up the Samsung TV integration."""
    if DOMAIN in config:
        hass.data[DOMAIN] = {}
        for entry_config in config[DOMAIN]:
            ip_address = await hass.async_add_executor_job(
                socket.gethostbyname, entry_config[CONF_HOST]
            )
            for key in SAMSMART_SCHEMA:
                hass.data[DOMAIN].setdefault(ip_address, {})[key] = entry_config.get(
                    key
                )
            if not entry_config.get(CONF_NAME):
                entry_config[CONF_NAME] = DEFAULT_NAME
            entry_config[SOURCE_IMPORT] = True
            hass.async_create_task(
                hass.config_entries.flow.async_init(
                    DOMAIN, context={"source": SOURCE_IMPORT}, data=entry_config
                )
            )

    return True
Esempio n. 20
0
async def async_setup_entry(hass: HomeAssistantType,
                            entry: ConfigEntry) -> bool:
    """Set up Sonarr from a config entry."""
    if not entry.options:
        options = {
            CONF_UPCOMING_DAYS:
            entry.data.get(CONF_UPCOMING_DAYS, DEFAULT_UPCOMING_DAYS),
            CONF_WANTED_MAX_ITEMS:
            entry.data.get(CONF_WANTED_MAX_ITEMS, DEFAULT_WANTED_MAX_ITEMS),
        }
        hass.config_entries.async_update_entry(entry, options=options)

    sonarr = Sonarr(
        host=entry.data[CONF_HOST],
        port=entry.data[CONF_PORT],
        api_key=entry.data[CONF_API_KEY],
        base_path=entry.data[CONF_BASE_PATH],
        session=async_get_clientsession(hass),
        tls=entry.data[CONF_SSL],
        verify_ssl=entry.data[CONF_VERIFY_SSL],
    )

    try:
        await sonarr.update()
    except SonarrError as err:
        raise ConfigEntryNotReady from err

    undo_listener = entry.add_update_listener(_async_update_listener)

    hass.data[DOMAIN][entry.entry_id] = {
        DATA_SONARR: sonarr,
        DATA_UNDO_UPDATE_LISTENER: undo_listener,
    }

    for component in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Esempio n. 21
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Establish connection with Daikin."""
    conf = entry.data
    # For backwards compat, set unique ID
    if entry.unique_id is None:
        hass.config_entries.async_update_entry(entry, unique_id=conf[KEY_MAC])
    elif ".local" in entry.unique_id:
        hass.config_entries.async_update_entry(entry, unique_id=conf[KEY_MAC])
    daikin_api = await daikin_api_setup(
        hass,
        conf[CONF_HOST],
        conf.get(CONF_API_KEY),
        conf.get(CONF_UUID),
        conf.get(CONF_PASSWORD),
    )
    if not daikin_api:
        return False
    hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: daikin_api})
    for component in COMPONENT_TYPES:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))
    return True
Esempio n. 22
0
async def async_setup_entry(hass: HomeAssistantType,
                            config_entry: ConfigEntry) -> bool:
    """Set up ClimaCell API from a config entry."""
    hass.data.setdefault(DOMAIN, {})

    # If config entry options not set up, set them up
    if not config_entry.options:
        hass.config_entries.async_update_entry(
            config_entry,
            options={
                CONF_TIMESTEP: DEFAULT_TIMESTEP,
            },
        )

    coordinator = ClimaCellDataUpdateCoordinator(
        hass,
        config_entry,
        ClimaCell(
            config_entry.data[CONF_API_KEY],
            config_entry.data.get(CONF_LATITUDE, hass.config.latitude),
            config_entry.data.get(CONF_LONGITUDE, hass.config.longitude),
            session=async_get_clientsession(hass),
        ),
        _set_update_interval(hass, config_entry),
    )

    await coordinator.async_refresh()

    if not coordinator.last_update_success:
        raise ConfigEntryNotReady

    hass.data[DOMAIN][config_entry.entry_id] = coordinator

    for platform in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(
                config_entry, platform))

    return True
Esempio n. 23
0
def get_remove_tasks(hass: HomeAssistantType, entities: Iterable[Entity]) -> List[asyncio.Task]:
    tasks = []

    for entity in entities:
        if entity.hass is None:
            entity.hass = hass
        tasks.append(
            hass.async_create_task(
                entity.async_remove()
            )
        )

    return tasks
Esempio n. 24
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Set up Somfy from a config entry."""
    def token_saver(token):
        _LOGGER.debug('Saving updated token')
        entry.data[CONF_TOKEN] = token
        hass.config_entries.async_update_entry(entry, data={**entry.data})

    # Force token update.
    from pymfy.api.somfy_api import SomfyApi
    hass.data[DOMAIN][API] = SomfyApi(
        entry.data['refresh_args']['client_id'],
        entry.data['refresh_args']['client_secret'],
        token=entry.data[CONF_TOKEN],
        token_updater=token_saver)

    await update_all_devices(hass)

    for component in SOMFY_COMPONENTS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Esempio n. 25
0
async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up the HEOS component."""
    if DOMAIN not in config:
        return True
    host = config[DOMAIN][CONF_HOST]
    entries = hass.config_entries.async_entries(DOMAIN)
    if not entries:
        # Create new entry based on config
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN, context={"source": "import"}, data={CONF_HOST: host}
            )
        )
    else:
        # Check if host needs to be updated
        entry = entries[0]
        if entry.data[CONF_HOST] != host:
            entry.data[CONF_HOST] = host
            entry.title = format_title(host)
            hass.config_entries.async_update_entry(entry)

    return True
Esempio n. 26
0
async def async_get_registry(hass: HomeAssistantType) -> ZhaDeviceStorage:
    """Return zha device storage instance."""
    task = hass.data.get(DATA_REGISTRY)

    if task is None:
        async def _load_reg() -> ZhaDeviceStorage:
            registry = ZhaDeviceStorage(hass)
            await registry.async_load()
            return registry

        task = hass.data[DATA_REGISTRY] = hass.async_create_task(_load_reg())

    return cast(ZhaDeviceStorage, await task)
Esempio n. 27
0
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:

    hass.data.setdefault(DOMAIN, {})
    conf = config.get(DOMAIN)  # type: ConfigType

    if conf is None:
        # If we have a config entry, setup is done by that config entry.
        # If there is no config entry, this should fail.
        return bool(hass.config_entries.async_entries(DOMAIN))

    hass.data[DOMAIN][DATA_HAVCS_CONFIG] = conf

    if not [
            entry for entry in hass.config_entries.async_entries(DOMAIN)
            if entry.source == config_entries.SOURCE_IMPORT
    ]:
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN,
                context={'source': config_entries.SOURCE_IMPORT},
                data={'platform': conf.get(CONF_PLATFORM)}))
    return True
Esempio n. 28
0
async def async_setup(hass: HomeAssistantType, config: dict) -> bool:
    """Set up the Ezviz integration."""
    hass.data.setdefault(DOMAIN, {})
    conf = config.get(DOMAIN, EZVIZ_SCHEMA({}))
    hass.data[DOMAIN] = {"config": conf}

    if hass.config_entries.async_entries(DOMAIN):
        return True

    if ACC_USERNAME or ACC_PASSWORD or CONF_REGION not in conf:
        return True

    if ACC_USERNAME or ACC_PASSWORD or CONF_REGION in conf:
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN,
                context={"source": SOURCE_IMPORT},
                data=config[DOMAIN],
            )
        )

    return True
Esempio n. 29
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Set up Somfy from a config entry."""
    # Backwards compat
    if "auth_implementation" not in entry.data:
        hass.config_entries.async_update_entry(
            entry, data={
                **entry.data, "auth_implementation": DOMAIN
            })

    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            hass, entry))

    hass.data[DOMAIN][API] = api.ConfigEntrySomfyApi(hass, entry,
                                                     implementation)

    await update_all_devices(hass)

    device_registry = await dr.async_get_registry(hass)

    devices = hass.data[DOMAIN][DEVICES]
    hubs = [
        device for device in devices if Category.HUB.value in device.categories
    ]

    for hub in hubs:
        device_registry.async_get_or_create(
            config_entry_id=entry.entry_id,
            identifiers={(DOMAIN, hub.id)},
            manufacturer="Somfy",
            name=hub.name,
            model=hub.type,
        )

    for component in SOMFY_COMPONENTS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Esempio n. 30
0
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
    hass.data[DOMAIN] = {}
    myconfig = {
        "mindst": config[DOMAIN][CONF_MIN_DST],
        "numofd": config[DOMAIN][CONF_NUMBER_OF_DAYS],
        "tz": config[DOMAIN][CONF_TIME_ZONE],
        "token": config[DOMAIN][CONF_TOKEN],
        "devs": config[DOMAIN][CONF_DEVICES],
        "haddr": config["http"]["base_url"],
    }

    sensors_gps = hass.data[DOMAIN]["sensors_gps"] = SensorsGps(hass,myconfig)

    try:
        await sensors_gps.update()
    except:
        _LOGGER.warning("Error creating sensors")
        return False

    async_track_time_interval(hass, sensors_gps.async_update, timedelta(seconds=60))

    for platform in SUPPORTED_DOMAINS:
        hass.async_create_task(async_load_platform(hass, platform, DOMAIN, {}, config))

    try:
        hass.http.register_view(Route(hass, myconfig))
        hass.components.frontend.async_register_built_in_panel(
            "iframe",
            "Routes",
            "mdi:routes",
            "myroute",
            {"url": "/route/route.html"},
            require_admin=False,
        )
    except:
        _LOGGER.error("Error creating panel")
        return False

    return True
Esempio n. 31
0
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
    """Set up the UniFi Protect components."""
    conf = config.get(DOMAIN, None)
    if not conf:
        return True

    configured_controllers = {
        entry.data.get(CONF_HOST)
        for entry in hass.config_entries.async_entries(DOMAIN)
    }

    hass.data.setdefault(DOMAIN, {})

    for controller_config in conf:
        if controller_config[CONF_HOST] not in configured_controllers:
            hass.async_create_task(
                hass.config_entries.flow.async_init(
                    DOMAIN,
                    context={"source": SOURCE_USER},
                    data=controller_config))

    return True
Esempio n. 32
0
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
    """Set up the MySensors component."""
    hass.data[DOMAIN] = {DATA_HASS_CONFIG: config}

    if DOMAIN not in config or bool(hass.config_entries.async_entries(DOMAIN)):
        return True

    config = config[DOMAIN]
    user_inputs = [
        {
            CONF_DEVICE: gw[CONF_DEVICE],
            CONF_BAUD_RATE: gw[CONF_BAUD_RATE],
            CONF_TCP_PORT: gw[CONF_TCP_PORT],
            CONF_TOPIC_OUT_PREFIX: gw.get(CONF_TOPIC_OUT_PREFIX, ""),
            CONF_TOPIC_IN_PREFIX: gw.get(CONF_TOPIC_IN_PREFIX, ""),
            CONF_RETAIN: config[CONF_RETAIN],
            CONF_VERSION: config[CONF_VERSION],
            CONF_PERSISTENCE_FILE: gw.get(CONF_PERSISTENCE_FILE)
            # nodes config ignored at this time. renaming nodes can now be done from the frontend.
        }
        for gw in config[CONF_GATEWAYS]
    ]
    user_inputs = [
        {k: v for k, v in userinput.items() if v is not None}
        for userinput in user_inputs
    ]

    # there is an actual configuration in configuration.yaml, so we have to process it
    for user_input in user_inputs:
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                DOMAIN,
                context={"source": config_entries.SOURCE_IMPORT},
                data=user_input,
            )
        )

    return True
Esempio n. 33
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Establish connection with Comfort Cloud."""
    from . import pcomfortcloud

    conf = entry.data
    if PANASONIC_DEVICES not in hass.data:
        hass.data[PANASONIC_DEVICES] = []

    username = conf[CONF_USERNAME]
    password = conf[CONF_PASSWORD]
    force_outside_sensor = entry.options.get(CONF_FORCE_OUTSIDE_SENSOR,
                                             DEFAULT_FORCE_OUTSIDE_SENSOR)
    if CONF_FORCE_OUTSIDE_SENSOR in conf:
        force_outside_sensor = conf[CONF_FORCE_OUTSIDE_SENSOR]
    enable_daily_energy_sensor = entry.options.get(
        CONF_ENABLE_DAILY_ENERGY_SENSOR, DEFAULT_ENABLE_DAILY_ENERGY_SENSOR)

    api = pcomfortcloud.Session(username, password, verifySsl=False)
    devices = await hass.async_add_executor_job(api.get_devices)
    for device in devices:
        try:
            api_device = PanasonicApiDevice(hass, api, device,
                                            force_outside_sensor,
                                            enable_daily_energy_sensor)
            await api_device.update()
            if enable_daily_energy_sensor:
                await api_device.update_energy()
            hass.data[PANASONIC_DEVICES].append(api_device)
        except Exception as e:
            _LOGGER.warning(f"Failed to setup device: {device['name']} ({e})")

    if hass.data[PANASONIC_DEVICES]:
        for component in COMPONENT_TYPES:
            hass.async_create_task(
                hass.config_entries.async_forward_entry_setup(
                    entry, component))

    return True
Esempio n. 34
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Set up Ketra platforms from config entry."""

    installation_id = entry.data.get("installation_id")
    oauth_token = entry.data.get(CONF_ACCESS_TOKEN)

    hub = await N4Hub.get_hub(installation_id, oauth_token, loop=hass.loop)
    _LOGGER.info(
        "Discovered N4 Hub at endpoint '%s' for installation '%s'",
        hub.url_base,
        installation_id,
    )

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.unique_id] = {
        "common_platform": KetraPlatformCommon(hass, hub, _LOGGER)
    }

    for platform in KETRA_PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, platform))

    return True
Esempio n. 35
0
async def async_setup_entry(hass: HomeAssistantType,
                            entry: ConfigEntry) -> bool:
    """Set up Lyric from a config entry."""
    conf = hass.data[DATA_LYRIC_CONFIG]

    client_id = conf[CONF_CLIENT_ID]
    client_secret = conf[CONF_CLIENT_SECRET]
    token = entry.data[CONF_TOKEN]
    token_cache_file = hass.config.path(CONF_LYRIC_CONFIG_FILE)

    lyric = Lyric(app_name='Home Assistant',
                  client_id=client_id,
                  client_secret=client_secret,
                  token=token,
                  token_cache_file=token_cache_file)

    hass.data.setdefault(DOMAIN, {})[DATA_LYRIC_CLIENT] = LyricClient(lyric)

    for component in 'climate', 'sensor':
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Esempio n. 36
0
async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up the Withings component."""
    conf = config.get(DOMAIN)
    if not conf:
        return True

    hass.data[DOMAIN] = {const.CONFIG: conf}

    base_url = conf.get(const.BASE_URL, hass.config.api.base_url).rstrip('/')

    # We don't pull default values from conf because the config
    # schema would have validated it for us.
    for profile in conf.get(const.PROFILES):
        config_flow.register_flow_implementation(hass,
                                                 conf.get(const.CLIENT_ID),
                                                 conf.get(const.CLIENT_SECRET),
                                                 base_url, profile)

    hass.async_create_task(
        hass.config_entries.flow.async_init(
            DOMAIN, context={'source': const.SOURCE_USER}, data={}))

    return True
Esempio n. 37
0
async def async_get_registry(hass: HomeAssistantType) -> ZhaStorage:
    """Return zha device storage instance."""
    task = hass.data.get(DATA_REGISTRY)

    if task is None:

        async def _load_reg() -> ZhaStorage:
            registry = ZhaStorage(hass)
            await registry.async_load()
            return registry

        task = hass.data[DATA_REGISTRY] = hass.async_create_task(_load_reg())

    return cast(ZhaStorage, await task)
Esempio n. 38
0
async def async_setup_platform(
    hass: HomeAssistantType,
    config: ConfigType,
    async_add_entities: Callable[[List[Entity], bool], None],
    discovery_info: Any = None,
) -> None:
    """Import the platform into a config entry."""
    if len(hass.config_entries.async_entries(DOMAIN)) > 0:
        return True

    config[CONF_BASE_PATH] = f"{config[CONF_URLBASE]}{DEFAULT_BASE_PATH}"
    config[CONF_UPCOMING_DAYS] = int(config[CONF_DAYS])
    config[CONF_VERIFY_SSL] = False

    del config[CONF_DAYS]
    del config[CONF_INCLUDED]
    del config[CONF_MONITORED_CONDITIONS]
    del config[CONF_URLBASE]

    hass.async_create_task(
        hass.config_entries.flow.async_init(DOMAIN,
                                            context={"source": SOURCE_IMPORT},
                                            data=config))
Esempio n. 39
0
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry) -> bool:
    """Set up Minecraft Server from a config entry."""
    domain_data = hass.data.setdefault(DOMAIN, {})

    # Create and store server instance.
    unique_id = config_entry.unique_id
    _LOGGER.debug(
        "Creating server instance for '%s' (%s)",
        config_entry.data[CONF_NAME],
        config_entry.data[CONF_HOST],
    )
    server = MinecraftServer(hass, unique_id, config_entry.data)
    domain_data[unique_id] = server
    await server.async_update()
    server.start_periodic_update()

    # Set up platforms.
    for platform in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(config_entry, platform)
        )

    return True
Esempio n. 40
0
async def async_setup_entry(hass: HomeAssistantType, entry: config_entries.ConfigEntry):
    """Set up an access point from a config entry."""
    client = Client(entry.data[CONF_HOST], entry.data[CONF_PORT])

    config = hass.data[DOMAIN_DATA_CONFIG].get(
        (entry.data[CONF_HOST], entry.data[CONF_PORT]),
        DEVICE_SCHEMA(
            {CONF_HOST: entry.data[CONF_HOST], CONF_PORT: entry.data[CONF_PORT]}
        ),
    )

    hass.data[DOMAIN_DATA_ENTRIES][entry.entry_id] = {
        "client": client,
        "config": config,
    }

    asyncio.ensure_future(_run_client(hass, client, config[CONF_SCAN_INTERVAL]))

    hass.async_create_task(
        hass.config_entries.async_forward_entry_setup(entry, "media_player")
    )

    return True
Esempio n. 41
0
async def async_setup_entry(hass: HomeAssistantType,
                            entry: ConfigEntry) -> bool:
    """Set up Canary from a config entry."""
    if not entry.options:
        options = {
            CONF_FFMPEG_ARGUMENTS:
            entry.data.get(CONF_FFMPEG_ARGUMENTS, DEFAULT_FFMPEG_ARGUMENTS),
            CONF_TIMEOUT:
            entry.data.get(CONF_TIMEOUT, DEFAULT_TIMEOUT),
        }
        hass.config_entries.async_update_entry(entry, options=options)

    try:
        canary_api = await hass.async_add_executor_job(
            _get_canary_api_instance, entry)
    except (ConnectTimeout, HTTPError) as error:
        _LOGGER.error("Unable to connect to Canary service: %s", str(error))
        raise ConfigEntryNotReady from error

    coordinator = CanaryDataUpdateCoordinator(hass, api=canary_api)
    await coordinator.async_refresh()

    if not coordinator.last_update_success:
        raise ConfigEntryNotReady

    undo_listener = entry.add_update_listener(_async_update_listener)

    hass.data[DOMAIN][entry.entry_id] = {
        DATA_COORDINATOR: coordinator,
        DATA_UNDO_UPDATE_LISTENER: undo_listener,
    }

    for platform in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, platform))

    return True
Esempio n. 42
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Establish connection with Neohub"""
    conf = entry.data
    hub = await neohub_api_setup(hass, conf[CONF_HOST])

    hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: hub})

    # determining mac address is only possible on local subnet
    # not if running in a non-bridged docker container, for example.
    mac = get_mac_from_host(conf[CONF_HOST])
    _LOGGER.info("neohub host: %s mac: %s" % (conf[CONF_HOST], mac))
    if mac is None:
        conns = {('hub_ip', conf[CONF_HOST])}
        idents = {(DOMAIN, conf[CONF_HOST])}
    else:
        conns = {(CONNECTION_NETWORK_MAC, mac)}
        idents = {(DOMAIN, mac)}

    _LOGGER.info("Adding neohub to device registry, entry_id: %s" %
                 entry.entry_id)
    # add to device registry
    dev_reg = await dr.async_get_registry(hass)
    dev_reg.async_get_or_create(
        config_entry_id=entry.entry_id,
        connections=conns,
        identifiers=idents,
        manufacturer='Heatmiser',
        name='NeoHub',
        model=hub.dcb.get('DEVICE_ID'),
        sw_version=hub.dcb.get('Firmware version'),
    )

    # set up devices for: climate. switch, sensor?
    for component in COMPONENT_TYPES:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))
    return True
Esempio n. 43
0
async def async_setup(hass: HomeAssistantType, config: ConfigType):
    """Set up the mobile app component."""
    store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
    app_config = await store.async_load()
    if app_config is None:
        app_config = {
            DATA_BINARY_SENSOR: {},
            DATA_CONFIG_ENTRIES: {},
            DATA_DELETED_IDS: [],
            DATA_DEVICES: {},
            DATA_SENSOR: {}
        }

    hass.data[DOMAIN] = {
        DATA_BINARY_SENSOR: app_config.get(DATA_BINARY_SENSOR, {}),
        DATA_CONFIG_ENTRIES: {},
        DATA_DELETED_IDS: app_config.get(DATA_DELETED_IDS, []),
        DATA_DEVICES: {},
        DATA_SENSOR: app_config.get(DATA_SENSOR, {}),
        DATA_STORE: store,
    }

    hass.http.register_view(RegistrationsView())
    register_websocket_handlers(hass)

    for deleted_id in hass.data[DOMAIN][DATA_DELETED_IDS]:
        try:
            webhook_register(hass, DOMAIN, "Deleted Webhook", deleted_id,
                             handle_webhook)
        except ValueError:
            pass

    hass.async_create_task(discovery.async_load_platform(
        hass, 'notify', DOMAIN, {}, config))

    return True
Esempio n. 44
0
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
    """Initialize config entry which represents an installed SmartApp."""
    from pysmartthings import SmartThings

    if not hass.config.api.base_url.lower().startswith('https://'):
        _LOGGER.warning("The 'base_url' of the 'http' component must be "
                        "configured and start with 'https://'")
        return False

    api = SmartThings(async_get_clientsession(hass),
                      entry.data[CONF_ACCESS_TOKEN])

    remove_entry = False
    try:
        # See if the app is already setup. This occurs when there are
        # installs in multiple SmartThings locations (valid use-case)
        manager = hass.data[DOMAIN][DATA_MANAGER]
        smart_app = manager.smartapps.get(entry.data[CONF_APP_ID])
        if not smart_app:
            # Validate and setup the app.
            app = await api.app(entry.data[CONF_APP_ID])
            smart_app = setup_smartapp(hass, app)

        # Validate and retrieve the installed app.
        installed_app = await validate_installed_app(
            api, entry.data[CONF_INSTALLED_APP_ID])

        # Get devices and their current status
        devices = await api.devices(
            location_ids=[installed_app.location_id])

        async def retrieve_device_status(device):
            try:
                await device.status.refresh()
            except ClientResponseError:
                _LOGGER.debug("Unable to update status for device: %s (%s), "
                              "the device will be ignored",
                              device.label, device.device_id, exc_info=True)
                devices.remove(device)

        await asyncio.gather(*[retrieve_device_status(d)
                               for d in devices.copy()])

        # Setup device broker
        broker = DeviceBroker(hass, devices,
                              installed_app.installed_app_id)
        broker.event_handler_disconnect = \
            smart_app.connect_event(broker.event_handler)
        hass.data[DOMAIN][DATA_BROKERS][entry.entry_id] = broker

    except ClientResponseError as ex:
        if ex.status in (401, 403):
            _LOGGER.exception("Unable to setup config entry '%s' - please "
                              "reconfigure the integration", entry.title)
            remove_entry = True
        else:
            _LOGGER.debug(ex, exc_info=True)
            raise ConfigEntryNotReady
    except (ClientConnectionError, RuntimeWarning) as ex:
        _LOGGER.debug(ex, exc_info=True)
        raise ConfigEntryNotReady

    if remove_entry:
        hass.async_create_task(
            hass.config_entries.async_remove(entry.entry_id))
        # only create new flow if there isn't a pending one for SmartThings.
        flows = hass.config_entries.flow.async_progress()
        if not [flow for flow in flows if flow['handler'] == DOMAIN]:
            hass.async_create_task(
                hass.config_entries.flow.async_init(
                    DOMAIN, context={'source': 'import'}))
        return False

    for component in SUPPORTED_PLATFORMS:
        hass.async_create_task(hass.config_entries.async_forward_entry_setup(
            entry, component))
    return True
Esempio n. 45
0
async def async_setup_entry(hass: HomeAssistantType,
                            entry: ConfigEntry) -> bool:
    """Set up the esphome component."""
    # pylint: disable=redefined-outer-name
    from aioesphomeapi import APIClient, APIConnectionError

    hass.data.setdefault(DOMAIN, {})

    host = entry.data[CONF_HOST]
    port = entry.data[CONF_PORT]
    password = entry.data[CONF_PASSWORD]

    cli = APIClient(hass.loop, host, port, password,
                    client_info="Home Assistant {}".format(const.__version__))

    # Store client in per-config-entry hass.data
    store = Store(hass, STORAGE_VERSION, STORAGE_KEY.format(entry.entry_id),
                  encoder=JSONEncoder)
    entry_data = hass.data[DOMAIN][entry.entry_id] = RuntimeEntryData(
        client=cli,
        entry_id=entry.entry_id,
        store=store,
    )

    async def on_stop(event: Event) -> None:
        """Cleanup the socket client on HA stop."""
        await _cleanup_instance(hass, entry)

    entry_data.cleanup_callbacks.append(
        hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_stop)
    )

    @callback
    def async_on_state(state: 'EntityState') -> None:
        """Send dispatcher updates when a new state is received."""
        entry_data.async_update_state(hass, state)

    @callback
    def async_on_service_call(service: 'ServiceCall') -> None:
        """Call service when user automation in ESPHome config is triggered."""
        domain, service_name = service.service.split('.', 1)
        service_data = service.data

        if service.data_template:
            try:
                data_template = {key: Template(value) for key, value in
                                 service.data_template.items()}
                template.attach(hass, data_template)
                service_data.update(template.render_complex(
                    data_template, service.variables))
            except TemplateError as ex:
                _LOGGER.error('Error rendering data template: %s', ex)
                return

        hass.async_create_task(hass.services.async_call(
            domain, service_name, service_data, blocking=True))

    async def send_home_assistant_state(entity_id: str, _,
                                        new_state: Optional[State]) -> None:
        """Forward Home Assistant states to ESPHome."""
        if new_state is None:
            return
        await cli.send_home_assistant_state(entity_id, new_state.state)

    @callback
    def async_on_state_subscription(entity_id: str) -> None:
        """Subscribe and forward states for requested entities."""
        unsub = async_track_state_change(
            hass, entity_id, send_home_assistant_state)
        entry_data.disconnect_callbacks.append(unsub)
        # Send initial state
        hass.async_create_task(send_home_assistant_state(
            entity_id, None, hass.states.get(entity_id)))

    async def on_login() -> None:
        """Subscribe to states and list entities on successful API login."""
        try:
            entry_data.device_info = await cli.device_info()
            entry_data.available = True
            await _async_setup_device_registry(hass, entry,
                                               entry_data.device_info)
            entry_data.async_update_device_state(hass)

            entity_infos = await cli.list_entities()
            entry_data.async_update_static_infos(hass, entity_infos)
            await cli.subscribe_states(async_on_state)
            await cli.subscribe_service_calls(async_on_service_call)
            await cli.subscribe_home_assistant_states(
                async_on_state_subscription)

            hass.async_create_task(entry_data.async_save_to_store())
        except APIConnectionError as err:
            _LOGGER.warning("Error getting initial data: %s", err)
            # Re-connection logic will trigger after this
            await cli.disconnect()

    try_connect = await _setup_auto_reconnect_logic(hass, cli, entry, host,
                                                    on_login)

    # This is a bit of a hack: We schedule complete_setup into the
    # event loop and return immediately (return True)
    #
    # Usually, we should avoid that so that HA can track which components
    # have been started successfully and which failed to be set up.
    # That doesn't work here for two reasons:
    #  - We have our own re-connect logic
    #  - Before we do the first try_connect() call, we need to make sure
    #    all dispatcher event listeners have been connected, so
    #    async_forward_entry_setup needs to be awaited. However, if we
    #    would await async_forward_entry_setup() in async_setup_entry(),
    #    we would end up with a deadlock.
    #
    # Solution is: complete the setup outside of the async_setup_entry()
    # function. HA will wait until the first connection attempt is made
    # before starting up (as it should), but if the first connection attempt
    # fails we will schedule all next re-connect attempts outside of the
    # tracked tasks (hass.loop.create_task). This way HA won't stall startup
    # forever until a connection is successful.

    async def complete_setup() -> None:
        """Complete the config entry setup."""
        tasks = []
        for component in HA_COMPONENTS:
            tasks.append(hass.config_entries.async_forward_entry_setup(
                entry, component))
        await asyncio.wait(tasks)

        infos = await entry_data.async_load_from_store()
        entry_data.async_update_static_infos(hass, infos)

        # If first connect fails, the next re-connect will be scheduled
        # outside of _pending_task, in order not to delay HA startup
        # indefinitely
        await try_connect(is_disconnect=False)

    hass.async_create_task(complete_setup())
    return True
Esempio n. 46
0
async def async_setup_entry(hass: HomeAssistantType,
                            config_entry: ConfigEntry):
    """Set up UPnP/IGD device from a config entry."""
    domain_data = hass.data[DOMAIN]
    conf = domain_data['config']

    # discover and construct
    device = await async_discover_and_construct(hass,
                                                config_entry.data.get('udn'))
    if not device:
        _LOGGER.info('Unable to create UPnP/IGD, aborting')
        return False

    # 'register'/save UDN
    config_entry.data['udn'] = device.udn
    hass.data[DOMAIN]['devices'][device.udn] = device
    hass.config_entries.async_update_entry(entry=config_entry,
                                           data=config_entry.data)

    # create device registry entry
    device_registry = await dr.async_get_registry(hass)
    device_registry.async_get_or_create(
        config_entry_id=config_entry.entry_id,
        connections={
            (dr.CONNECTION_UPNP, device.udn)
        },
        identifiers={
            (DOMAIN, device.udn)
        },
        name=device.name,
        manufacturer=device.manufacturer,
    )

    # set up sensors
    if conf.get(CONF_ENABLE_SENSORS):
        _LOGGER.debug('Enabling sensors')

        # register sensor setup handlers
        hass.async_create_task(hass.config_entries.async_forward_entry_setup(
            config_entry, 'sensor'))

    # set up port mapping
    if conf.get(CONF_ENABLE_PORT_MAPPING):
        _LOGGER.debug('Enabling port mapping')
        local_ip = domain_data['local_ip']
        ports = conf.get('ports', {})

        hass_port = None
        if hasattr(hass, 'http'):
            hass_port = hass.http.server_port

        ports = _substitute_hass_ports(ports, hass_port=hass_port)
        await device.async_add_port_mappings(ports, local_ip)

    # set up port mapping deletion on stop-hook
    async def delete_port_mapping(event):
        """Delete port mapping on quit."""
        _LOGGER.debug('Deleting port mappings')
        await device.async_delete_port_mappings()

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, delete_port_mapping)

    return True