Exemple #1
0
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
                            async_add_devices):
    current_entity_platform = entity_platform.current_platform.get()
    final_config = hass.data.get(DATA_FINAL_CONFIG,
                                 {}).get(config_entry.entry_id)

    log_prefix = _make_log_prefix(config_entry, current_entity_platform, 's')

    if final_config is None:
        _LOGGER.error(log_prefix + 'Final configuration not yet present')
        raise PlatformNotReady

    _LOGGER.debug(log_prefix + 'Begin entry setup')

    await async_discover(current_entity_platform=current_entity_platform,
                         config_entry=config_entry,
                         final_config=final_config,
                         async_add_devices=async_add_devices)

    _LOGGER.debug(log_prefix + 'End entry setup')
Exemple #2
0
async def async_discover(
        current_entity_platform: EntityPlatform, config_entry: ConfigEntry,
        final_config: ConfigType,
        async_add_devices: Callable[[List[Entity], bool], Any]) -> None:
    log_prefix = _make_log_prefix(config_entry, current_entity_platform,
                                  'discvr')

    hass = current_entity_platform.hass
    api: Optional[API] = hass.data.get(DATA_API_OBJECTS,
                                       {}).get(config_entry.entry_id)

    if api is None:
        _LOGGER.error(log_prefix + 'API object not yet present')
        raise PlatformNotReady

    _LOGGER.debug(log_prefix + 'Begin entity discovery')

    # Fetch necessary data: Accounts
    accounts: List[BaseAccount] = await api.get_accounts(
        return_unsupported_accounts=False, suppress_unsupported_logging=True)

    _LOGGER.debug(log_prefix + f'Fetched {len(accounts)} accounts')

    # Account post-fetch filtering
    if CONF_FILTER in final_config:
        accounts_filter = final_config[CONF_FILTER]
        accounts = [
            account for account in accounts
            if accounts_filter[account.account_code]
        ]

        _LOGGER.info(log_prefix +
                     f'Processing {len(accounts)} accounts after filtering')

    # Execute entity discovery calls
    tasks = [
        hass.async_create_task(
            async_discover_func(
                current_entity_platform=current_entity_platform,
                config_entry=config_entry,
                final_config=final_config,
                accounts=accounts))
        for async_discover_func in (async_discover_accounts,
                                    async_discover_invoices,
                                    async_discover_meters)
    ]

    _LOGGER.debug(log_prefix + f'Calling {len(tasks)} discovery sub-functions')

    await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)

    _LOGGER.debug(log_prefix + 'Discovery sub-functions calling finished')

    # Collect new entities and internal tasks
    new_entities = []
    new_tasks = []

    for task in tasks:
        entities, tasks = task.result()
        new_entities.extend(entities)
        new_tasks.extend(tasks)

    # Wait until internal tasks are complete (if present)
    if new_tasks:
        _LOGGER.debug(log_prefix +
                      f'Executing {len(new_tasks)} scheduled async tasks')
        await asyncio.wait(tasks)

    # Add new entities to HA registry (if present)
    if new_entities:
        _LOGGER.debug(log_prefix + f'Adding {len(new_entities)} new entities')
        async_add_devices(new_entities, True)

    _LOGGER.debug(log_prefix + 'End entity discovery')
Exemple #3
0
async def _common_discover_entities(
    current_entity_platform: EntityPlatform,
    config_entry: ConfigEntry,
    source_objects: Iterable[TObject],
    object_code_getter: Callable[[TObject], TIdentifier],
    entity_cls: Type[TSensor],
    final_config: Optional[ConfigType] = None,
    existing_entities: Optional[List[TSensor]] = None,
    sensor_type_name: Optional[str] = None,
    entity_code_getter: Callable[[TSensor], TIdentifier] = None,
    log_prefix: Optional[str] = None,
) -> DiscoveryReturnType:
    """
    Common entity discovery helper.
    :param current_entity_platform: Entity platform used
    :param config_entry: Configuration entry
    :param final_config: Final configuration data
    :param source_objects: Objects to use when creating entities
    :param object_code_getter: Getter for identifier for objects
    :param entity_cls: Entity class (subclass of `MESEntity`)
    :param existing_entities: (optional) Existing entities list
                              (default: retrieved at runtime)
    :param sensor_type_name: (optional) Sensor type name for log prefixing
                             (default: derrived from configuration key)
    :param entity_code_getter: (optional) Getter for identifier for entities
                               (default: `code` property of provided entity class)
    :param log_prefix: (optional) Log prefix to prepend to internal loggin
                       (default: empty string)
    :return: Tuple[new entities list, async tasks]
    """
    hass = current_entity_platform.hass
    config_key = entity_cls.config_key

    if final_config is None:
        final_config = hass.data.get(DATA_FINAL_CONFIG,
                                     {}).get(config_entry.entry_id)
        if final_config is None:
            raise ValueError(
                'Final configuration not available for entry "%s"' %
                (config_entry.entry_id, ))

    if sensor_type_name is None:
        sensor_type_name = config_key
        if sensor_type_name.endswith('s'):
            sensor_type_name = sensor_type_name[:-1]

    if log_prefix is None:
        log_prefix = _make_log_prefix(config_entry, current_entity_platform,
                                      'discvr', sensor_type_name)

    if entity_code_getter is None:
        entity_code_getter = entity_cls.code

    if current_entity_platform is None:
        current_entity_platform = entity_platform.current_platform.get()

    if existing_entities is None:
        existing_entities = hass.data\
            .get(DATA_ENTITIES, {})\
            .get(config_entry.entry_id, {})\
            .get(config_key, [])

    entities = []
    tasks = []

    added_entities: Set[TSensor] = set(existing_entities or [])

    entity_filter = final_config[CONF_ENTITIES][config_key]
    name_formats = final_config[CONF_NAME_FORMAT][config_key]
    scan_intervals = final_config[CONF_SCAN_INTERVAL][config_key]

    for iter_object in source_objects:
        identifier = object_code_getter(iter_object)
        granular_log_prefix = _make_log_prefix(config_entry,
                                               current_entity_platform,
                                               'discvr',
                                               sensor_type_name.ljust(7),
                                               '*' + identifier[-5:])

        if not entity_filter[identifier]:
            _LOGGER.info(granular_log_prefix +
                         'Skipping setup/update due to filter')
            continue

        obj_entity = None

        for entity in added_entities:
            if entity_code_getter(entity) == identifier:
                obj_entity = entity
                break

        entity_log_prefix = _make_log_prefix(config_entry,
                                             current_entity_platform, 'entity',
                                             sensor_type_name.ljust(7),
                                             '*' + identifier[-5:])

        if obj_entity is None:
            _LOGGER.debug(granular_log_prefix + 'Setting up entity')
            entities.append(
                entity_cls.async_discover_create(iter_object,
                                                 name_formats[identifier],
                                                 scan_intervals[identifier],
                                                 entity_log_prefix))

        else:
            added_entities.remove(obj_entity)

            if obj_entity.enabled:
                _LOGGER.debug(granular_log_prefix + 'Updating entity')
                update_task = obj_entity.async_discover_update(
                    iter_object, name_formats[identifier],
                    scan_intervals[identifier], entity_log_prefix)
                if update_task is not None:
                    tasks.append(update_task)

    if entities:
        register_update_services(entity_cls, current_entity_platform,
                                 log_prefix)

    if added_entities:
        _LOGGER.info(
            log_prefix +
            f'Removing {len(added_entities)} {sensor_type_name} entities')

        tasks.extend(get_remove_tasks(hass, added_entities))

    return entities, tasks