Пример #1
0
 async def _async_get_and_check_device_info(self):
     """Try to get the device info."""
     _port, _method, info = await async_get_device_info(
         self.hass, self._bridge, self._host)
     if not info:
         if not _method:
             LOGGER.debug(
                 "Samsung host %s is not supported by either %s or %s methods",
                 self._host,
                 METHOD_LEGACY,
                 METHOD_WEBSOCKET,
             )
             raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
         return False
     dev_info = info.get("device", {})
     device_type = dev_info.get("type")
     if device_type != "Samsung SmartTV":
         raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
     self._model = dev_info.get("modelName")
     name = dev_info.get("name")
     self._name = name.replace("[TV] ", "") if name else device_type
     self._title = f"{self._name} ({self._model})"
     self._udn = _strip_uuid(dev_info.get("udn", info["id"]))
     if mac := mac_from_device_info(info):
         self._mac = mac
Пример #2
0
 async def _async_set_unique_id_or_update(
     self, isy_mac: str, ip_address: str, port: int | None
 ) -> None:
     """Abort and update the ip address on change."""
     existing_entry = await self.async_set_unique_id(isy_mac)
     if not existing_entry:
         return
     if existing_entry.source == config_entries.SOURCE_IGNORE:
         raise data_entry_flow.AbortFlow("already_configured")
     parsed_url = urlparse(existing_entry.data[CONF_HOST])
     if parsed_url.hostname != ip_address:
         new_netloc = ip_address
         if port:
             new_netloc = f"{ip_address}:{port}"
         elif parsed_url.port:
             new_netloc = f"{ip_address}:{parsed_url.port}"
         self.hass.config_entries.async_update_entry(
             existing_entry,
             data={
                 **existing_entry.data,
                 CONF_HOST: urlunparse(
                     (
                         parsed_url.scheme,
                         new_netloc,
                         parsed_url.path,
                         parsed_url.query,
                         parsed_url.fragment,
                         None,
                     )
                 ),
             },
         )
     raise data_entry_flow.AbortFlow("already_configured")
Пример #3
0
 def _try_connect(self):
     """Try to connect and check auth."""
     for method in SUPPORTED_METHODS:
         self._bridge = SamsungTVBridge.get_bridge(method, self._host)
         result = self._bridge.try_connect()
         if result == RESULT_SUCCESS:
             return
         if result != RESULT_CANNOT_CONNECT:
             raise data_entry_flow.AbortFlow(result)
     LOGGER.debug("No working config found")
     raise data_entry_flow.AbortFlow(RESULT_CANNOT_CONNECT)
Пример #4
0
    def _abort_if_unique_id_configured(self) -> None:
        """Abort if the unique ID is already configured."""
        if self.unique_id is None:
            return

        if self.unique_id in self._async_current_ids():
            raise data_entry_flow.AbortFlow("already_configured")
Пример #5
0
 async def _async_start_discovery_with_mac_address(self) -> None:
     """Start discovery."""
     assert self._host is not None
     if (entry := self._async_update_existing_host_entry()) and entry.unique_id:
         # If we have the unique id and the mac we abort
         # as we do not need anything else
         raise data_entry_flow.AbortFlow("already_configured")
Пример #6
0
    async def async_set_device(self, device, raise_on_progress=True):
        """Define a device for the config flow."""
        supported_types = {
            device_type
            for _, device_types in DOMAINS_AND_TYPES
            for device_type in device_types
        }
        if device.type not in supported_types:
            LOGGER.error(
                "Unsupported device: %s. If it worked before, please open "
                "an issue at https://github.com/home-assistant/core/issues",
                hex(device.devtype),
            )
            raise data_entry_flow.AbortFlow("not_supported")

        await self.async_set_unique_id(device.mac.hex(),
                                       raise_on_progress=raise_on_progress)
        self.device = device

        # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
        self.context["title_placeholders"] = {
            "name": device.name,
            "model": device.model,
            "host": device.host[0],
        }
Пример #7
0
    async def async_step_zeroconf(self, discovery_info):
        """Handle zeroconf discovery."""
        _LOGGER.debug("Async_Step_Zeroconf start")
        if discovery_info is None:
            return self.async_abort(reason="cannot_connect")
        _LOGGER.debug("Async_Step_Zeroconf discovery info %s" % discovery_info)

        # if it's not a MLGW or BLGW device, then abort
        if not discovery_info.get("name"):
            return self.async_abort(reason="not_mlgw_device")

        if not (discovery_info["name"].startswith("MLGW")
                or discovery_info["name"].startswith("BLGW")):
            return self.async_abort(reason="not_mlgw_device")

        # Hostname is format: mlgw.local.
        self.host = discovery_info["hostname"].rstrip(".")
        _LOGGER.debug("Async_Step_Zeroconf Hostname %s" % self.host)

        try:
            sn = await mlgw_get_xmpp_serial(self.host)
        except Exception as e:
            _LOGGER.debug("Exception %s" % str(e))
            return self.async_abort(reason="cannot_connect")
        if sn is not None:
            await self.async_set_unique_id(sn)
            self._abort_if_unique_id_configured()
        if sn is None:
            raise data_entry_flow.AbortFlow("no_serial_number")

        _LOGGER.debug("Async_Step_Zeroconf Awaiting Confirmation %s sn: %s" %
                      (self.host, sn))

        return await self.async_step_zeroconf_confirm()
Пример #8
0
    async def async_set_unique_id(
        self, unique_id: Optional[str] = None, *, raise_on_progress: bool = True
    ) -> Optional[ConfigEntry]:
        """Set a unique ID for the config flow.

        Returns optionally existing config entry with same ID.
        """
        if unique_id is None:
            self.context["unique_id"] = None  # pylint: disable=no-member
            return None

        if raise_on_progress:
            for progress in self._async_in_progress():
                if progress["context"].get("unique_id") == unique_id:
                    raise data_entry_flow.AbortFlow("already_in_progress")

        self.context["unique_id"] = unique_id  # pylint: disable=no-member

        # Abort discoveries done using the default discovery unique id
        assert self.hass is not None
        if unique_id != DEFAULT_DISCOVERY_UNIQUE_ID:
            for progress in self._async_in_progress():
                if progress["context"].get("unique_id") == DEFAULT_DISCOVERY_UNIQUE_ID:
                    self.hass.config_entries.flow.async_abort(progress["flow_id"])

        for entry in self._async_current_entries():
            if entry.unique_id == unique_id:
                return entry

        return None
Пример #9
0
    def _abort_if_unique_id_configured(
        self,
        updates: Optional[Dict[Any, Any]] = None,
        reload_on_update: bool = True,
    ) -> None:
        """Abort if the unique ID is already configured."""
        assert self.hass
        if self.unique_id is None:
            return

        for entry in self._async_current_entries():
            if entry.unique_id == self.unique_id:
                if updates is not None:
                    changed = self.hass.config_entries.async_update_entry(
                        entry, data={**entry.data, **updates}
                    )
                    if (
                        changed
                        and reload_on_update
                        and entry.state in (ENTRY_STATE_LOADED, ENTRY_STATE_SETUP_RETRY)
                    ):
                        self.hass.async_create_task(
                            self.hass.config_entries.async_reload(entry.entry_id)
                        )
                raise data_entry_flow.AbortFlow("already_configured")
Пример #10
0
    def _abort_if_unique_id_configured(
        self,
        updates: Optional[Dict[Any, Any]] = None,
        reload_on_update: bool = True,
    ) -> None:
        """Abort if the unique ID is already configured."""
        if self.unique_id is None:
            return

        for entry in self._async_current_entries(include_ignore=True):
            if entry.unique_id == self.unique_id:
                if updates is not None:
                    changed = self.hass.config_entries.async_update_entry(
                        entry, data={
                            **entry.data,
                            **updates
                        })
                    if (changed and reload_on_update and entry.state
                            in (ENTRY_STATE_LOADED, ENTRY_STATE_SETUP_RETRY)):
                        self.hass.async_create_task(
                            self.hass.config_entries.async_reload(
                                entry.entry_id))
                # Allow ignored entries to be configured on manual user step
                if entry.source == SOURCE_IGNORE and self.source == SOURCE_USER:
                    continue
                raise data_entry_flow.AbortFlow("already_configured")
Пример #11
0
 async def _async_set_name_host_from_input(self, user_input):
     try:
         self._host = await self.hass.async_add_executor_job(
             socket.gethostbyname, user_input[CONF_HOST])
     except socket.gaierror as err:
         raise data_entry_flow.AbortFlow(RESULT_UNKNOWN_HOST) from err
     self._name = user_input.get(CONF_NAME, self._host)
     self._title = self._name
Пример #12
0
 async def _async_get_and_check_device_info(self) -> bool:
     """Try to get the device info."""
     _port, _method, info = await async_get_device_info(
         self.hass, self._bridge, self._host)
     if not info:
         if not _method:
             LOGGER.debug(
                 "Samsung host %s is not supported by either %s or %s methods",
                 self._host,
                 METHOD_LEGACY,
                 METHOD_WEBSOCKET,
             )
             raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
         return False
     dev_info = info.get("device", {})
     if (device_type := dev_info.get("type")) != "Samsung SmartTV":
         raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
Пример #13
0
 async def _async_start_discovery_for_host(self, host):
     """Start discovery for a host."""
     if entry := self._async_update_existing_host_entry(host):
         if entry.unique_id:
             # Let the flow continue to fill the missing
             # unique id as we may be able to obtain it
             # in the next step
             raise data_entry_flow.AbortFlow("already_configured")
Пример #14
0
 async def _async_set_unique_id_from_udn(self, raise_on_progress=True):
     """Set the unique id from the udn."""
     assert self._host is not None
     await self.async_set_unique_id(self._udn,
                                    raise_on_progress=raise_on_progress)
     if (entry := self._async_update_existing_host_entry()
         ) and _entry_is_complete(entry):
         raise data_entry_flow.AbortFlow("already_configured")
Пример #15
0
 async def _async_set_device_unique_id(self,
                                       raise_on_progress: bool = True
                                       ) -> None:
     """Set device unique_id."""
     if not await self._async_get_and_check_device_info():
         raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
     await self._async_set_unique_id_from_udn(raise_on_progress)
     self._async_update_and_abort_for_matching_unique_id()
Пример #16
0
 async def _async_get_and_check_device_info(self):
     """Try to get the device info."""
     info = await async_get_device_info(self.hass, self._bridge, self._host)
     if not info:
         raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
     dev_info = info.get("device", {})
     device_type = dev_info.get("type")
     if device_type != "Samsung SmartTV":
         raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
     self._model = dev_info.get("modelName")
     name = dev_info.get("name")
     self._name = name.replace("[TV] ", "") if name else device_type
     self._title = f"{self._name} ({self._model})"
     self._udn = _strip_uuid(dev_info.get("udn", info["id"]))
     if dev_info.get("networkType") == "wireless" and dev_info.get(
             "wifiMac"):
         self._mac = format_mac(dev_info.get("wifiMac"))
     self._device_info = info
Пример #17
0
 async def async_step_import(self, user_input=None):
     """Import a config entry."""
     if self._async_current_entries():
         for entry in self._async_current_entries(include_ignore=True):
             if user_input is not None:
                 self.hass.config_entries.async_update_entry(
                     entry, data=user_input
                 )
                 raise data_entry_flow.AbortFlow("already_configured")
     else:
         return self.async_create_entry(title="RCSLink Config",
                                        data=user_input)
Пример #18
0
 def _async_check_and_update_in_progress(self, host: str,
                                         unique_id: str) -> None:
     """Check for in-progress flows and update them with identifiers if needed."""
     for flow in self._async_in_progress(include_uninitialized=True):
         context = flow["context"]
         if (context.get("source") != config_entries.SOURCE_ZEROCONF
                 or context.get(CONF_ADDRESS) != host):
             continue
         if ("all_identifiers" in context
                 and unique_id not in context["all_identifiers"]):
             # Add potentially new identifiers from this device to the existing flow
             context["all_identifiers"].append(unique_id)
         raise data_entry_flow.AbortFlow("already_in_progress")
Пример #19
0
    def _abort_if_unique_id_configured(self, updates: Dict[Any, Any] = None) -> None:
        """Abort if the unique ID is already configured."""
        assert self.hass
        if self.unique_id is None:
            return

        for entry in self._async_current_entries():
            if entry.unique_id == self.unique_id:
                if updates is not None and not updates.items() <= entry.data.items():
                    self.hass.config_entries.async_update_entry(
                        entry, data={**entry.data, **updates}
                    )
                raise data_entry_flow.AbortFlow("already_configured")
Пример #20
0
 async def async_step_ssdp(self, discovery_info: DiscoveryInfoType):
     """Handle a flow initialized by ssdp discovery."""
     self._udn = _strip_uuid(discovery_info[ATTR_UPNP_UDN])
     await self._async_set_unique_id_from_udn()
     await self._async_start_discovery_for_host(
         urlparse(discovery_info[ATTR_SSDP_LOCATION]).hostname)
     self._manufacturer = discovery_info[ATTR_UPNP_MANUFACTURER]
     if not self._manufacturer or not self._manufacturer.lower().startswith(
             "samsung"):
         raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
     self._name = self._title = self._model = discovery_info.get(
         ATTR_UPNP_MODEL_NAME)
     self.context["title_placeholders"] = {"device": self._title}
     return await self.async_step_confirm()
Пример #21
0
    async def _async_handle_discovery_without_unique_id(self) -> None:
        """Mark this flow discovered, without a unique identifier.

        If a flow initiated by discovery, doesn't have a unique ID, this can
        be used alternatively. It will ensure only 1 flow is started and only
        when the handler has no existing config entries.

        It ensures that the discovery can be ignored by the user.
        """
        if self.unique_id is not None:
            return

        # Abort if the handler has config entries already
        if self._async_current_entries():
            raise data_entry_flow.AbortFlow("already_configured")

        # Use an special unique id to differentiate
        await self.async_set_unique_id(DEFAULT_DISCOVERY_UNIQUE_ID)
        self._abort_if_unique_id_configured()

        # Abort if any other flow for this handler is already in progress
        if self._async_in_progress():
            raise data_entry_flow.AbortFlow("already_in_progress")
Пример #22
0
    def _async_check_configured_entry(self) -> None:
        """Check if entry is configured, update unique_id if needed."""
        for entry in self._async_current_entries(include_ignore=False):
            if entry.data[CONF_HOST] != self._host:
                continue

            if self._uuid and not entry.unique_id:
                _LOGGER.debug(
                    "Updating unique_id for host %s, unique_id: %s",
                    self._host,
                    self._uuid,
                )
                self.hass.config_entries.async_update_entry(entry, unique_id=self._uuid)

            raise data_entry_flow.AbortFlow("already_configured")
Пример #23
0
    async def _async_discovery_handler(self, ip_address):
        """Start the user flow from any discovery."""
        self.context[CONF_IP_ADDRESS] = ip_address
        self._abort_if_unique_id_configured({CONF_IP_ADDRESS: ip_address})

        self._async_abort_entries_match({CONF_IP_ADDRESS: ip_address})

        self._ip_address = ip_address
        for progress in self._async_in_progress():
            if progress.get("context",
                            {}).get(CONF_IP_ADDRESS) == self._ip_address:
                raise data_entry_flow.AbortFlow("already_in_progress")

        self._device_type = DEVICE_TYPE_ISMARTGATE
        return await self.async_step_user()
Пример #24
0
    async def async_set_unique_id(
        self, unique_id: str, *, raise_on_progress: bool = True
    ) -> Optional[ConfigEntry]:
        """Set a unique ID for the config flow.

        Returns optionally existing config entry with same ID.
        """
        if raise_on_progress:
            for progress in self._async_in_progress():
                if progress["context"].get("unique_id") == unique_id:
                    raise data_entry_flow.AbortFlow("already_in_progress")

        self.context["unique_id"] = unique_id  # pylint: disable=no-member

        for entry in self._async_current_entries():
            if entry.unique_id == unique_id:
                return entry

        return None
Пример #25
0
    async def async_set_device(self, device, raise_on_progress=True):
        """Define a device for the config flow."""
        if device.type not in DEVICE_TYPES:
            _LOGGER.error(
                "Unsupported device: %s. If it worked before, please open "
                "an issue at https://github.com/home-assistant/core/issues",
                hex(device.devtype),
            )
            raise data_entry_flow.AbortFlow("not_supported")

        await self.async_set_unique_id(device.mac.hex(),
                                       raise_on_progress=raise_on_progress)
        self.device = device

        self.context["title_placeholders"] = {
            "name": device.name,
            "model": device.model,
            "host": device.host[0],
        }
Пример #26
0
    async def async_step_dhcp(self, discovery_info):
        """Handle dhcp discovery of a Squeezebox player."""
        _LOGGER.debug("Reached dhcp discovery of a player with info: %s",
                      discovery_info)
        await self.async_set_unique_id(format_mac(discovery_info[MAC_ADDRESS]))
        self._abort_if_unique_id_configured()

        _LOGGER.debug("Configuring dhcp player with unique id: %s",
                      self.unique_id)

        registry = async_get(self.hass)

        # if we have detected this player, do nothing. if not, there must be a server out there for us to configure, so start the normal user flow (which tries to autodetect server)
        if registry.async_get_entity_id(MP_DOMAIN, DOMAIN,
                                        self.unique_id) is not None:
            # this player is already known, so do nothing other than mark as configured
            raise data_entry_flow.AbortFlow("already_configured")

        # if the player is unknown, then we likely need to configure its server
        return await self.async_step_user()
Пример #27
0
    async def async_found_zeroconf_device(self, user_input=None):
        """Handle device found after Zeroconf discovery."""
        # Suppose we have a device with three services: A, B and C. Let's assume
        # service A is discovered by Zeroconf, triggering a device scan that also finds
        # service B but *not* C. An identifier is picked from one of the services and
        # used as unique_id. The select process is deterministic (let's say in order A,
        # B and C) but in practice that doesn't matter. So, a flow is set up for the
        # device with unique_id set to "A" for services A and B.
        #
        # Now, service C is found and the same thing happens again but only service B
        # is found. In this case, unique_id will be set to "B" which is problematic
        # since both flows really represent the same device. They will however end up
        # as two separate flows.
        #
        # To solve this, all identifiers found during a device scan is stored as
        # "all_identifiers" in the flow context. When a new service is discovered, the
        # code below will check these identifiers for all active flows and abort if a
        # match is found. Before aborting, the original flow is updated with any
        # potentially new identifiers. In the example above, when service C is
        # discovered, the identifier of service C will be inserted into
        # "all_identifiers" of the original flow (making the device complete).
        for flow in self._async_in_progress():
            for identifier in self.atv.all_identifiers:
                if identifier not in flow["context"].get("all_identifiers", []):
                    continue

                # Add potentially new identifiers from this device to the existing flow
                identifiers = set(flow["context"]["all_identifiers"])
                identifiers.update(self.atv.all_identifiers)
                flow["context"]["all_identifiers"] = list(identifiers)

                raise data_entry_flow.AbortFlow("already_in_progress")

        self.context["all_identifiers"] = self.atv.all_identifiers

        # Also abort if an integration with this identifier already exists
        await self.async_set_unique_id(self.device_identifier)
        self._abort_if_unique_id_configured()

        self.context["identifier"] = self.unique_id
        return await self.async_step_confirm()
Пример #28
0
 def _abort_if_manufacturer_is_not_samsung(self) -> None:
     if not self._manufacturer or not self._manufacturer.lower().startswith(
             "samsung"):
         raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
Пример #29
0
class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """Handle a Samsung TV config flow."""

    VERSION = 2

    def __init__(self):
        """Initialize flow."""
        self._reauth_entry = None
        self._host = None
        self._mac = None
        self._udn = None
        self._manufacturer = None
        self._model = None
        self._name = None
        self._title = None
        self._id = None
        self._bridge = None
        self._device_info = None

    def _get_entry_from_bridge(self):
        """Get device entry."""
        data = {
            CONF_HOST: self._host,
            CONF_MAC: self._mac,
            CONF_MANUFACTURER: self._manufacturer or DEFAULT_MANUFACTURER,
            CONF_METHOD: self._bridge.method,
            CONF_MODEL: self._model,
            CONF_NAME: self._name,
            CONF_PORT: self._bridge.port,
        }
        if self._bridge.token:
            data[CONF_TOKEN] = self._bridge.token
        return self.async_create_entry(
            title=self._title,
            data=data,
        )

    async def _async_set_device_unique_id(self, raise_on_progress=True):
        """Set device unique_id."""
        await self._async_get_and_check_device_info()
        await self._async_set_unique_id_from_udn(raise_on_progress)

    async def _async_set_unique_id_from_udn(self, raise_on_progress=True):
        """Set the unique id from the udn."""
        assert self._host is not None
        await self.async_set_unique_id(self._udn,
                                       raise_on_progress=raise_on_progress)
        self._async_update_existing_host_entry(self._host)
        updates = {CONF_HOST: self._host}
        if self._mac:
            updates[CONF_MAC] = self._mac
        self._abort_if_unique_id_configured(updates=updates)

    def _try_connect(self):
        """Try to connect and check auth."""
        for method in SUPPORTED_METHODS:
            self._bridge = SamsungTVBridge.get_bridge(method, self._host)
            result = self._bridge.try_connect()
            if result == RESULT_SUCCESS:
                return
            if result != RESULT_CANNOT_CONNECT:
                raise data_entry_flow.AbortFlow(result)
        LOGGER.debug("No working config found")
        raise data_entry_flow.AbortFlow(RESULT_CANNOT_CONNECT)

    async def _async_get_and_check_device_info(self):
        """Try to get the device info."""
        info = await async_get_device_info(self.hass, self._bridge, self._host)
        if not info:
            raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
        dev_info = info.get("device", {})
        device_type = dev_info.get("type")
        if device_type != "Samsung SmartTV":
            raise data_entry_flow.AbortFlow(RESULT_NOT_SUPPORTED)
        self._model = dev_info.get("modelName")
        name = dev_info.get("name")
        self._name = name.replace("[TV] ", "") if name else device_type
        self._title = f"{self._name} ({self._model})"
        self._udn = _strip_uuid(dev_info.get("udn", info["id"]))
        if dev_info.get("networkType") == "wireless" and dev_info.get(
                "wifiMac"):
            self._mac = format_mac(dev_info.get("wifiMac"))
        self._device_info = info

    async def async_step_import(self, user_input=None):
        """Handle configuration by yaml file."""
        # We need to import even if we cannot validate
        # since the TV may be off at startup
        await self._async_set_name_host_from_input(user_input)
        self._async_abort_entries_match({CONF_HOST: self._host})
        if user_input.get(CONF_PORT) in WEBSOCKET_PORTS:
            user_input[CONF_METHOD] = METHOD_WEBSOCKET
        else:
            user_input[CONF_METHOD] = METHOD_LEGACY
            user_input[CONF_PORT] = LEGACY_PORT
        user_input[CONF_MANUFACTURER] = DEFAULT_MANUFACTURER
        return self.async_create_entry(
            title=self._title,
            data=user_input,
        )

    async def _async_set_name_host_from_input(self, user_input):
        try:
            self._host = await self.hass.async_add_executor_job(
                socket.gethostbyname, user_input[CONF_HOST])
        except socket.gaierror as err:
            raise data_entry_flow.AbortFlow(RESULT_UNKNOWN_HOST) from err
        self._name = user_input.get(CONF_NAME, self._host)
        self._title = self._name

    async def async_step_user(self, user_input=None):
        """Handle a flow initialized by the user."""
        if user_input is not None:
            await self._async_set_name_host_from_input(user_input)
            await self.hass.async_add_executor_job(self._try_connect)
            self._async_abort_entries_match({CONF_HOST: self._host})
            if self._bridge.method != METHOD_LEGACY:
                # Legacy bridge does not provide device info
                await self._async_set_device_unique_id(raise_on_progress=False)
            return self._get_entry_from_bridge()

        return self.async_show_form(step_id="user", data_schema=DATA_SCHEMA)

    @callback
    def _async_update_existing_host_entry(self, host):
        for entry in self._async_current_entries(include_ignore=False):
            if entry.data[CONF_HOST] != host:
                continue
            entry_kw_args = {}
            if self.unique_id and entry.unique_id is None:
                entry_kw_args["unique_id"] = self.unique_id
            if self._mac and not entry.data.get(CONF_MAC):
                data_copy = dict(entry.data)
                data_copy[CONF_MAC] = self._mac
                entry_kw_args["data"] = data_copy
            if entry_kw_args:
                self.hass.config_entries.async_update_entry(
                    entry, **entry_kw_args)
            return entry
        return None

    async def _async_start_discovery(self):
        """Start discovery."""
        assert self._host is not None
        if entry := self._async_update_existing_host_entry(self._host):
            if entry.unique_id:
                # Let the flow continue to fill the missing
                # unique id as we may be able to obtain it
                # in the next step
                raise data_entry_flow.AbortFlow("already_configured")

        self.context[CONF_HOST] = self._host
        for progress in self._async_in_progress():
            if progress.get("context", {}).get(CONF_HOST) == self._host:
                raise data_entry_flow.AbortFlow("already_in_progress")
Пример #30
0
 async def async_step_init(self, user_input=None):
     raise data_entry_flow.AbortFlow("mock-reason", {"placeholder": "yo"})