Ejemplo n.º 1
0
    async def _async_update_data(self) -> dict[str, Device]:
        """Fetch Overkiz data via event listener."""
        try:
            events = await self.client.fetch_events()
        except BadCredentialsException as exception:
            raise ConfigEntryAuthFailed("Invalid authentication.") from exception
        except TooManyConcurrentRequestsException as exception:
            raise UpdateFailed("Too many concurrent requests.") from exception
        except TooManyRequestsException as exception:
            raise UpdateFailed("Too many requests, try again later.") from exception
        except MaintenanceException as exception:
            raise UpdateFailed("Server is down for maintenance.") from exception
        except InvalidEventListenerIdException as exception:
            raise UpdateFailed(exception) from exception
        except TimeoutError as exception:
            raise UpdateFailed("Failed to connect.") from exception
        except (ServerDisconnectedError, NotAuthenticatedException):
            self.executions = {}

            # During the relogin, similar exceptions can be thrown.
            try:
                await self.client.login()
                self.devices = await self._get_devices()
            except BadCredentialsException as exception:
                raise ConfigEntryAuthFailed("Invalid authentication.") from exception
            except TooManyRequestsException as exception:
                raise UpdateFailed("Too many requests, try again later.") from exception

            return self.devices

        for event in events:
            LOGGER.debug(event)

            if event_handler := EVENT_HANDLERS.get(event.name):
                await event_handler(self, event)
Ejemplo n.º 2
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up upon config entry in user interface."""
    conf = entry.data
    username = conf[CONF_USERNAME]
    password = conf[CONF_PASSWORD]

    if CONF_USERCODES not in conf:
        # should only happen for those who used UI before we added usercodes
        raise ConfigEntryAuthFailed(
            "No usercodes in TotalConnect configuration")

    temp_codes = conf[CONF_USERCODES]
    usercodes = {int(code): temp_codes[code] for code in temp_codes}

    try:
        client = await hass.async_add_executor_job(TotalConnectClient,
                                                   username, password,
                                                   usercodes)
    except AuthenticationError as exception:
        raise ConfigEntryAuthFailed(
            "TotalConnect authentication failed during setup") from exception

    coordinator = TotalConnectDataUpdateCoordinator(hass, client)
    await coordinator.async_config_entry_first_refresh()

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.entry_id] = coordinator
    hass.config_entries.async_setup_platforms(entry, PLATFORMS)
    return True
Ejemplo n.º 3
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up upon config entry in user interface."""
    conf = entry.data
    username = conf[CONF_USERNAME]
    password = conf[CONF_PASSWORD]

    if CONF_USERCODES not in conf:
        # should only happen for those who used UI before we added usercodes
        raise ConfigEntryAuthFailed(
            "No usercodes in TotalConnect configuration")

    temp_codes = conf[CONF_USERCODES]
    usercodes = {int(code): temp_codes[code] for code in temp_codes}
    client = await hass.async_add_executor_job(
        TotalConnectClient.TotalConnectClient, username, password, usercodes)

    if not client.is_valid_credentials():
        raise ConfigEntryAuthFailed("TotalConnect authentication failed")

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

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Ejemplo n.º 4
0
    def connect_gateway(self):
        """Connect the gateway in a way that can called by async_add_executor_job."""
        try:
            self._gateway_device = gateway.Gateway(self._host, self._token)
            # get the gateway info
            self._gateway_info = self._gateway_device.info()
        except DeviceException as error:
            if isinstance(error.__cause__, ChecksumError):
                raise ConfigEntryAuthFailed(error) from error

            _LOGGER.error(
                "DeviceException during setup of xiaomi gateway with host %s: %s",
                self._host,
                error,
            )
            return False

        # get the connected sub devices
        use_cloud = self._use_cloud or self._gateway_info.model == GATEWAY_MODEL_EU
        if not use_cloud:
            # use local query (not supported by all gateway types)
            try:
                self._gateway_device.discover_devices()
            except DeviceException as error:
                _LOGGER.info(
                    "DeviceException during getting subdevices of xiaomi gateway"
                    " with host %s, trying cloud to obtain subdevices: %s",
                    self._host,
                    error,
                )
                use_cloud = True

        if use_cloud:
            # use miio-cloud
            if (self._cloud_username is None or self._cloud_password is None
                    or self._cloud_country is None):
                raise ConfigEntryAuthFailed(
                    "Missing cloud credentials in Xiaomi Miio configuration")

            try:
                miio_cloud = MiCloud(self._cloud_username,
                                     self._cloud_password)
                if not miio_cloud.login():
                    raise ConfigEntryAuthFailed(
                        "Could not login to Xiaomi Miio Cloud, check the credentials"
                    )
                devices_raw = miio_cloud.get_devices(self._cloud_country)
                self._gateway_device.get_devices_from_dict(devices_raw)
            except DeviceException as error:
                _LOGGER.error(
                    "DeviceException during setup of xiaomi gateway with host %s: %s",
                    self._host,
                    error,
                )
                return False

        return True
Ejemplo n.º 5
0
    async def _async_update_data(self):
        try:
            async with async_timeout.timeout(DEFAULT_TIMEOUT):
                # Retrieve the panel online status first
                panels = await self._client.list_control_panels()
                panel = next(
                    (panel
                     for panel in panels if panel.hash == self._panel_id),
                    None)

                # If the panel is no more available within the given. Raise config error as the user must
                # reconfigure it in order to  make it work again
                if not panel:
                    raise ConfigEntryAuthFailed(
                        f"Panel ID {self._panel_id} is no more linked to this user account"
                    )

                self._panel_entry = panel

                # If the panel is online, proceed with fetching its state
                # and return it right away
                if panel.online:
                    status = await self._client.get_panel_status(
                        control_panel_id=panel.hash,
                        pin=self._panel_pin)  # type: PanelStatus

                    # Store a dictionary for fast endpoint state access
                    self._state_by_endpoint = {
                        k.endpoint_id: k
                        for k in status.all_endpoints
                    }
                    return status

                # Otherwise, return None. Listeners will know that this means the device is offline
                return None

        except ElmaxBadPinError as err:
            raise ConfigEntryAuthFailed(
                "Control panel pin was refused") from err
        except ElmaxBadLoginError as err:
            raise ConfigEntryAuthFailed("Refused username/password") from err
        except ElmaxApiError as err:
            raise UpdateFailed(
                f"Error communicating with ELMAX API: {err}") from err
        except ElmaxNetworkError as err:
            raise UpdateFailed(
                "A network error occurred while communicating with Elmax cloud."
            ) from err
Ejemplo n.º 6
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up IntelliFire from a config entry."""
    LOGGER.debug("Setting up config entry: %s", entry.unique_id)

    if CONF_USERNAME not in entry.data:
        LOGGER.debug("Old config entry format detected: %s", entry.unique_id)
        raise ConfigEntryAuthFailed

    # Define the API Objects
    read_object = IntellifireAsync(entry.data[CONF_HOST])
    ift_control = IntellifireControlAsync(fireplace_ip=entry.data[CONF_HOST], )
    try:
        await ift_control.login(
            username=entry.data[CONF_USERNAME],
            password=entry.data[CONF_PASSWORD],
        )
    except (ConnectionError, ClientConnectionError) as err:
        raise ConfigEntryNotReady from err
    except LoginException as err:
        raise ConfigEntryAuthFailed(err) from err

    finally:
        await ift_control.close()

    # Define the update coordinator
    coordinator = IntellifireDataUpdateCoordinator(hass=hass,
                                                   read_api=read_object,
                                                   control_api=ift_control)

    await coordinator.async_config_entry_first_refresh()
    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Ejemplo n.º 7
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Deluge from a config entry."""
    host = entry.data[CONF_HOST]
    port = entry.data[CONF_PORT]
    username = entry.data[CONF_USERNAME]
    password = entry.data[CONF_PASSWORD]
    api = await hass.async_add_executor_job(
        DelugeRPCClient, host, port, username, password
    )
    api.web_port = entry.data[CONF_WEB_PORT]
    try:
        await hass.async_add_executor_job(api.connect)
    except (
        ConnectionRefusedError,
        socket.timeout,
        SSLError,
    ) as ex:
        raise ConfigEntryNotReady("Connection to Deluge Daemon failed") from ex
    except Exception as ex:  # pylint:disable=broad-except
        if type(ex).__name__ == "BadLoginError":
            raise ConfigEntryAuthFailed(
                "Credentials for Deluge client are not valid"
            ) from ex
        _LOGGER.error("Unknown error connecting to Deluge: %s", ex)

    coordinator = DelugeDataUpdateCoordinator(hass, api, entry)
    await coordinator.async_config_entry_first_refresh()
    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Ejemplo n.º 8
0
    async def async_update_data():
        """Fetch data from Mazda API."""
        try:
            vehicles = await with_timeout(mazda_client.get_vehicles())

            # The Mazda API can throw an error when multiple simultaneous requests are
            # made for the same account, so we can only make one request at a time here
            for vehicle in vehicles:
                vehicle["status"] = await with_timeout(
                    mazda_client.get_vehicle_status(vehicle["id"]))

                # If vehicle is electric, get additional EV-specific status info
                if vehicle["isElectric"]:
                    vehicle["evStatus"] = await with_timeout(
                        mazda_client.get_ev_vehicle_status(vehicle["id"]))

            hass.data[DOMAIN][entry.entry_id][DATA_VEHICLES] = vehicles

            return vehicles
        except MazdaAuthenticationException as ex:
            raise ConfigEntryAuthFailed(
                "Not authenticated with Mazda API") from ex
        except Exception as ex:
            _LOGGER.exception(
                "Unknown error occurred during Mazda update request: %s", ex)
            raise UpdateFailed(ex) from ex
Ejemplo n.º 9
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Uonet+ Vulcan integration."""
    hass.data.setdefault(DOMAIN, {})
    try:
        keystore = Keystore.load(entry.data["keystore"])
        account = Account.load(entry.data["account"])
        client = Vulcan(keystore, account, async_get_clientsession(hass))
        await client.select_student()
        students = await client.get_students()
        for student in students:
            if str(student.pupil.id) == str(entry.data["student_id"]):
                client.student = student
                break
    except UnauthorizedCertificateException as err:
        raise ConfigEntryAuthFailed(
            "The certificate is not authorized.") from err
    except ClientConnectorError as err:
        raise ConfigEntryNotReady(
            f"Connection error - please check your internet connection: {err}"
        ) from err
    hass.data[DOMAIN][entry.entry_id] = client

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True
Ejemplo n.º 10
0
    async def _async_update_data(self) -> None:
        """Get the latest data from Radarr."""
        start = dt_util.as_utc(dt_util.start_of_local_day().replace(microsecond=0))
        end = start + timedelta(days=self.config_entry.options[CONF_UPCOMING_DAYS])
        try:
            [
                self.system_status,
                self.rootfolder,
                self.calendar,
                self.commands,
            ] = await asyncio.gather(
                *[
                    self.api_client.async_get_system_status(),
                    self.api_client.async_get_root_folders(),
                    self.api_client.async_get_calendar(start_date=start, end_date=end),
                    self.api_client.async_get_commands(),
                ]
            )
            # Diskspace can timeout with large systems with remote mapped storage
            # We attempt to get total disk capacity first
            if not self.disk_space and not self.movies_count_enabled:
                self.disk_space = await self.api_client.async_get_diskspace()
            else:
                # Wait to get movie count after disk capacity is determined
                self.movies_count_enabled = True
                self.movies = cast(list, await self.api_client.async_get_movies())

        except exceptions.ArrConnectionException as ex:
            raise UpdateFailed(ex) from ex
        except exceptions.ArrAuthenticationException as ex:
            raise ConfigEntryAuthFailed(
                "API Key is no longer valid. Please reauthenticate"
            ) from ex
Ejemplo n.º 11
0
    async def _async_update_data(self) -> list[Sensor]:
        """Get the data for LaCrosse View."""
        now = datetime.utcnow()

        if self.last_update < now - timedelta(minutes=59):  # Get new token
            self.last_update = now
            try:
                await self.api.login(self.username, self.password)
            except LoginError as error:
                raise ConfigEntryAuthFailed from error

        # Get the timestamp for yesterday at 6 PM (this is what is used in the app, i noticed it when proxying the request)
        yesterday = now - timedelta(days=1)
        yesterday = yesterday.replace(hour=18, minute=0, second=0, microsecond=0)
        yesterday_timestamp = datetime.timestamp(yesterday)

        try:
            sensors = await self.api.get_sensors(
                location=Location(id=self.id, name=self.name),
                tz=self.hass.config.time_zone,
                start=str(int(yesterday_timestamp)),
                end=str(int(datetime.timestamp(now))),
            )
        except HTTPError as error:
            raise ConfigEntryNotReady from error

        # Verify that we have permission to read the sensors
        for sensor in sensors:
            if not sensor.permissions.get("read", False):
                raise ConfigEntryAuthFailed(
                    f"This account does not have permission to read {sensor.name}"
                )

        return sensors
Ejemplo n.º 12
0
    async def _async_update_data(self) -> list[UptimeRobotMonitor] | None:
        """Update data."""
        try:
            response = await self.api.async_get_monitors()
        except UptimeRobotAuthenticationException as exception:
            raise ConfigEntryAuthFailed(exception) from exception
        except UptimeRobotException as exception:
            raise UpdateFailed(exception) from exception
        else:
            if response.status != API_ATTR_OK:
                raise UpdateFailed(response.error.message)

        monitors: list[UptimeRobotMonitor] = response.data

        current_monitors = {
            list(device.identifiers)[0][1]
            for device in dr.async_entries_for_config_entry(
                self._device_registry, self._config_entry_id)
        }
        new_monitors = {str(monitor.id) for monitor in monitors}
        if stale_monitors := current_monitors - new_monitors:
            for monitor_id in stale_monitors:
                if device := self._device_registry.async_get_device({
                    (DOMAIN, monitor_id)
                }):
                    self._device_registry.async_remove_device(device.id)
Ejemplo n.º 13
0
async def async_setup_entry(hass, entry):
    """Set up a config entry for Apple TV."""
    if entry.options.get(CONF_RECONFIGURE, False):
        hass.config_entries.async_update_entry(
            entry, options={**entry.options, CONF_RECONFIGURE: False}
        )
        raise ConfigEntryAuthFailed("reconfiguration was requested")

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

    async def on_hass_stop(event):
        """Stop push updates when hass stops."""
        await manager.disconnect()

    entry.async_on_unload(
        hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop)
    )

    async def setup_platforms():
        """Set up platforms and initiate connection."""
        await asyncio.gather(
            *(
                hass.config_entries.async_forward_entry_setup(entry, platform)
                for platform in PLATFORMS
            )
        )
        await manager.init()

    hass.async_create_task(setup_platforms())

    entry.async_on_unload(entry.add_update_listener(async_config_entry_changed))

    return True
Ejemplo n.º 14
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Abode integration from a config entry."""
    username = entry.data[CONF_USERNAME]
    password = entry.data[CONF_PASSWORD]
    polling = entry.data[CONF_POLLING]
    cache = hass.config.path(DEFAULT_CACHEDB)

    # For previous config entries where unique_id is None
    if entry.unique_id is None:
        hass.config_entries.async_update_entry(
            entry, unique_id=entry.data[CONF_USERNAME]
        )

    try:
        abode = await hass.async_add_executor_job(
            Abode, username, password, True, True, True, cache
        )

    except AbodeAuthenticationException as ex:
        raise ConfigEntryAuthFailed(f"Invalid credentials: {ex}") from ex

    except (AbodeException, ConnectTimeout, HTTPError) as ex:
        raise ConfigEntryNotReady(f"Unable to connect to Abode: {ex}") from ex

    hass.data[DOMAIN] = AbodeSystem(abode, polling)

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    await setup_hass_events(hass)
    await hass.async_add_executor_job(setup_hass_services, hass)
    await hass.async_add_executor_job(setup_abode_events, hass)

    return True
Ejemplo n.º 15
0
    async def async_update(self) -> None:
        """Get updated data from SimpliSafe."""
        async def async_update_system(system: SystemV2 | SystemV3) -> None:
            """Update a system."""
            await system.async_update(cached=system.version != 3)
            self._async_process_new_notifications(system)

        tasks = [
            async_update_system(system) for system in self.systems.values()
        ]
        results = await asyncio.gather(*tasks, return_exceptions=True)

        for result in results:
            if isinstance(result, InvalidCredentialsError):
                raise ConfigEntryAuthFailed("Invalid credentials") from result

            if isinstance(result, EndpointUnavailableError):
                # In case the user attempts an action not allowed in their current plan,
                # we merely log that message at INFO level (so the user is aware,
                # but not spammed with ERROR messages that they cannot change):
                LOGGER.info(result)

            if isinstance(result, SimplipyError):
                raise UpdateFailed(
                    f"SimpliSafe error while updating: {result}")
Ejemplo n.º 16
0
async def async_setup_entry(hass, entry, async_add_entities):
    try:
        api = await hass.async_add_executor_job(WavinSentio,
                                                entry.data[CONF_USERNAME],
                                                entry.data[CONF_PASSWORD])
    except UnauthorizedException as err:
        raise ConfigEntryAuthFailed(err) from err

    rooms = await hass.async_add_executor_job(api.get_rooms,
                                              entry.data[CONF_LOCATION_ID])

    dataservice = WavinSentioClimateDataService(hass, api,
                                                entry.data[CONF_LOCATION_ID],
                                                rooms)
    dataservice.async_setup()
    await dataservice.coordinator.async_refresh()

    entities = []
    for room in rooms:
        ws = WavinSentioEntity(hass, room, dataservice)
        entities.append(ws)
    async_add_entities(entities)

    hass.async_create_task(
        hass.config_entries.async_forward_entry_setup(entry, "sensor"))
Ejemplo n.º 17
0
 async def _async_update_data(self) -> dict[Platform, dict[str, int | str]]:
     """Get the latest data from Deluge and updates the state."""
     data = {}
     try:
         data[Platform.SENSOR] = await self.hass.async_add_executor_job(
             self.api.call,
             "core.get_session_status",
             [
                 "upload_rate",
                 "download_rate",
                 "dht_upload_rate",
                 "dht_download_rate",
             ],
         )
         data[Platform.SWITCH] = await self.hass.async_add_executor_job(
             self.api.call, "core.get_torrents_status", {}, ["paused"])
     except (
             ConnectionRefusedError,
             socket.timeout,  # pylint:disable=no-member
             SSLError,
             FailedToReconnectException,
     ) as ex:
         raise UpdateFailed(
             f"Connection to Deluge Daemon Lost: {ex}") from ex
     except Exception as ex:  # pylint:disable=broad-except
         if type(ex).__name__ == "BadLoginError":
             raise ConfigEntryAuthFailed(
                 "Credentials for Deluge client are not valid") from ex
         LOGGER.error("Unknown error connecting to Deluge: %s", ex)
         raise ex
     return data
Ejemplo n.º 18
0
    async def async_get_events(self, hass, start_date,
                               end_date) -> list[CalendarEvent]:
        """Get all events in a specific time frame."""
        try:
            events = await get_lessons(
                self.client,
                date_from=start_date,
                date_to=end_date,
            )
        except UnauthorizedCertificateException as err:
            raise ConfigEntryAuthFailed(
                "The certificate is not authorized, please authorize integration again"
            ) from err
        except ClientConnectorError as err:
            if self.available:
                _LOGGER.warning(
                    "Connection error - please check your internet connection: %s",
                    err)
            events = []

        event_list = []
        for item in events:
            event = CalendarEvent(
                start=datetime.combine(item["date"], item["time"].from_),
                end=datetime.combine(item["date"], item["time"].to),
                summary=item["lesson"],
                location=item["room"],
                description=item["teacher"],
            )

            event_list.append(event)

        return event_list
Ejemplo n.º 19
0
 async def _async_update_trend():
     """Update the trend data."""
     try:
         await gateway.update_trend_data()
     except (SenseAuthenticationException, SenseMFARequiredException) as err:
         _LOGGER.warning("Sense authentication expired")
         raise ConfigEntryAuthFailed(err) from err
Ejemplo n.º 20
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Discord from a config entry."""
    nextcord.VoiceClient.warn_nacl = False
    discord_bot = nextcord.Client()
    try:
        await discord_bot.login(entry.data[CONF_API_TOKEN])
    except nextcord.LoginFailure as ex:
        raise ConfigEntryAuthFailed("Invalid token given") from ex
    except (ClientConnectorError, nextcord.HTTPException,
            nextcord.NotFound) as ex:
        raise ConfigEntryNotReady("Failed to connect") from ex
    finally:
        await discord_bot.close()

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

    hass.async_create_task(
        discovery.async_load_platform(
            hass,
            Platform.NOTIFY,
            DOMAIN,
            hass.data[DOMAIN][entry.entry_id],
            hass.data[DOMAIN],
        ))

    return True
Ejemplo n.º 21
0
    async def _setup_websocket(self) -> None:
        """Use WebSocket for updates."""

        try:
            self.logger.debug(
                "Connecting to ws://%s:%s",
                self.host,
                self.bridge.information.websocketPort,
            )
            await self.bridge.async_connect_websocket(
                self.host, self.bridge.information.websocketPort
            )
        except BridgeAuthenticationException as exception:
            if self.unsub:
                self.unsub()
                self.unsub = None
            raise ConfigEntryAuthFailed() from exception
        except (*BRIDGE_CONNECTION_ERRORS, ConnectionRefusedError) as exception:
            if self.unsub:
                self.unsub()
                self.unsub = None
            raise UpdateFailed(
                f"Could not connect to {self.title} ({self.host})."
            ) from exception
        asyncio.create_task(self._listen_for_events())

        async def close_websocket(_) -> None:
            """Close WebSocket connection."""
            await self.bridge.async_close_websocket()

        # Clean disconnect WebSocket on Home Assistant shutdown
        self.unsub = self.hass.bus.async_listen_once(
            EVENT_HOMEASSISTANT_STOP, close_websocket
        )
Ejemplo n.º 22
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up laundrify from a config entry."""

    session = async_get_clientsession(hass)
    api_client = LaundrifyAPI(entry.data[CONF_ACCESS_TOKEN], session)

    try:
        await api_client.validate_token()
    except UnauthorizedException as err:
        raise ConfigEntryAuthFailed("Invalid authentication") from err
    except ApiConnectionException as err:
        raise ConfigEntryNotReady("Cannot reach laundrify API") from err

    coordinator = LaundrifyUpdateCoordinator(hass, api_client,
                                             DEFAULT_POLL_INTERVAL)

    await coordinator.async_config_entry_first_refresh()

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

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Ejemplo n.º 23
0
    def setup(self) -> bool:
        """Set up the tankerkoenig API."""
        for station_id in self._selected_stations:
            try:
                station_data = pytankerkoenig.getStationData(
                    self._api_key, station_id)
            except pytankerkoenig.customException as err:
                if any(x in str(err).lower() for x in ("api-key", "apikey")):
                    raise ConfigEntryAuthFailed(err) from err
                station_data = {
                    "ok": False,
                    "message": err,
                    "exception": True,
                }

            if not station_data["ok"]:
                _LOGGER.error(
                    "Error when adding station %s:\n %s",
                    station_id,
                    station_data["message"],
                )
                continue
            self.add_station(station_data["station"])
        if len(self.stations) > 10:
            _LOGGER.warning(
                "Found more than 10 stations to check. "
                "This might invalidate your api-key on the long run. "
                "Try using a smaller radius")
        return True
Ejemplo n.º 24
0
    async def async_update() -> dict[str, dict[str, Any]]:
        """Get the latest data from the Notion API."""
        data: dict[str, dict[str, Any]] = {
            "bridges": {},
            "sensors": {},
            "tasks": {}
        }
        tasks = {
            "bridges": client.bridge.async_all(),
            "sensors": client.sensor.async_all(),
            "tasks": client.task.async_all(),
        }

        results = await asyncio.gather(*tasks.values(), return_exceptions=True)
        for attr, result in zip(tasks, results):
            if isinstance(result, InvalidCredentialsError):
                raise ConfigEntryAuthFailed(
                    "Invalid username and/or password") from result
            if isinstance(result, NotionError):
                raise UpdateFailed(
                    f"There was a Notion error while updating {attr}: {result}"
                ) from result
            if isinstance(result, Exception):
                raise UpdateFailed(
                    f"There was an unknown error while updating {attr}: {result}"
                ) from result

            for item in result:
                if attr == "bridges" and item["id"] not in data["bridges"]:
                    # If a new bridge is discovered, register it:
                    hass.async_create_task(
                        async_register_new_bridge(hass, item, entry))
                data[attr][item["id"]] = item

        return data
Ejemplo n.º 25
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up VLC media player Telnet from a config entry."""
    config = entry.data

    host = config[CONF_HOST]
    port = config[CONF_PORT]
    password = config[CONF_PASSWORD]

    vlc = Client(password=password, host=host, port=port)

    available = True

    try:
        await vlc.connect()
    except ConnectError as err:
        LOGGER.warning("Failed to connect to VLC: %s. Trying again", err)
        available = False

    if available:
        try:
            await vlc.login()
        except AuthError as err:
            await disconnect_vlc(vlc)
            raise ConfigEntryAuthFailed() from err

    domain_data = hass.data.setdefault(DOMAIN, {})
    domain_data[entry.entry_id] = {DATA_VLC: vlc, DATA_AVAILABLE: available}

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True
Ejemplo n.º 26
0
 async def _async_update_data(self) -> dict[Platform, dict[str, int | str]]:
     """Get the latest data from Deluge and updates the state."""
     data = {}
     try:
         _data = await self.hass.async_add_executor_job(
             self.api.call,
             "core.get_session_status",
             DATA_KEYS,
         )
         data[Platform.SENSOR] = {k.decode(): v for k, v in _data.items()}
         data[Platform.SWITCH] = await self.hass.async_add_executor_job(
             self.api.call, "core.get_torrents_status", {}, ["paused"]
         )
     except (
         ConnectionRefusedError,
         socket.timeout,
         SSLError,
         FailedToReconnectException,
     ) as ex:
         raise UpdateFailed(f"Connection to Deluge Daemon Lost: {ex}") from ex
     except Exception as ex:
         if type(ex).__name__ == "BadLoginError":
             raise ConfigEntryAuthFailed(
                 "Credentials for Deluge client are not valid"
             ) from ex
         LOGGER.error("Unknown error connecting to Deluge: %s", ex)
         raise ex
     return data
Ejemplo n.º 27
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up pushover from a config entry."""

    pushover_api = PushoverAPI(entry.data[CONF_API_KEY])
    try:
        await hass.async_add_executor_job(pushover_api.validate,
                                          entry.data[CONF_USER_KEY])

    except BadAPIRequestError as err:
        if "application token is invalid" in str(err):
            raise ConfigEntryAuthFailed(err) from err
        raise ConfigEntryNotReady(err) from err

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

    hass.async_create_task(
        discovery.async_load_platform(
            hass,
            Platform.NOTIFY,
            DOMAIN,
            {
                CONF_NAME: entry.data[CONF_NAME],
                CONF_USER_KEY: entry.data[CONF_USER_KEY],
                "entry_id": entry.entry_id,
            },
            hass.data[DATA_HASS_CONFIG],
        ))

    return True
Ejemplo n.º 28
0
    async def async_connect_device(self, host, token):
        """Connect to the Xiaomi Device."""
        _LOGGER.debug("Initializing with host %s (token %s...)", host, token[:5])

        try:
            self._device = Device(host, token)
            # get the device info
            self._device_info = await self._hass.async_add_executor_job(
                self._device.info
            )
        except DeviceException as error:
            if isinstance(error.__cause__, ChecksumError):
                raise ConfigEntryAuthFailed(error) from error

            _LOGGER.error(
                "DeviceException during setup of xiaomi device with host %s: %s",
                host,
                error,
            )
            return False

        _LOGGER.debug(
            "%s %s %s detected",
            self._device_info.model,
            self._device_info.firmware_version,
            self._device_info.hardware_version,
        )
        return True
Ejemplo n.º 29
0
    def _setup(self, hass):
        """Rachio device setup."""
        rachio = self.rachio

        response = rachio.person.info()
        if is_invalid_auth_code(int(response[0][KEY_STATUS])):
            raise ConfigEntryAuthFailed(f"API key error: {response}")
        if int(response[0][KEY_STATUS]) != HTTPStatus.OK:
            raise ConfigEntryNotReady(f"API Error: {response}")
        self._id = response[1][KEY_ID]

        # Use user ID to get user data
        data = rachio.person.get(self._id)
        if is_invalid_auth_code(int(data[0][KEY_STATUS])):
            raise ConfigEntryAuthFailed(f"User ID error: {data}")
        if int(data[0][KEY_STATUS]) != HTTPStatus.OK:
            raise ConfigEntryNotReady(f"API Error: {data}")
        self.username = data[1][KEY_USERNAME]
        devices = data[1][KEY_DEVICES]
        for controller in devices:
            webhooks = rachio.notification.get_device_webhook(
                controller[KEY_ID])[1]
            # The API does not provide a way to tell if a controller is shared
            # or if they are the owner. To work around this problem we fetch the webhooks
            # before we setup the device so we can skip it instead of failing.
            # webhooks are normally a list, however if there is an error
            # rachio hands us back a dict
            if isinstance(webhooks, dict):
                if webhooks.get("code") == PERMISSION_ERROR:
                    _LOGGER.info(
                        "Not adding controller '%s', only controllers owned by '%s' may be added",
                        controller[KEY_NAME],
                        self.username,
                    )
                else:
                    _LOGGER.error(
                        "Failed to add rachio controller '%s' because of an error: %s",
                        controller[KEY_NAME],
                        webhooks.get("error", "Unknown Error"),
                    )
                continue

            rachio_iro = RachioIro(hass, rachio, controller, webhooks)
            rachio_iro.setup()
            self._controllers.append(rachio_iro)

        _LOGGER.info('Using Rachio API as user "%s"', self.username)
Ejemplo n.º 30
0
async def refresh_tokens(hass: HomeAssistant, entry: ConfigEntry):
    """Store updated authentication and director tokens in hass.data, and schedule next token refresh."""
    config = entry.data
    verify_ssl_session = aiohttp_client.async_get_clientsession(hass)

    account = C4Account(config[CONF_USERNAME], config[CONF_PASSWORD],
                        verify_ssl_session)
    try:
        await account.getAccountBearerToken()
    except client_exceptions.ClientError as exception:
        raise ConfigEntryNotReady(exception) from exception
    except BadCredentials as exception:
        raise ConfigEntryAuthFailed(exception) from exception

    controller_unique_id = config[CONF_CONTROLLER_UNIQUE_ID]
    director_token_dict = await account.getDirectorBearerToken(
        controller_unique_id)
    no_verify_ssl_session = aiohttp_client.async_get_clientsession(
        hass, verify_ssl=False)

    director = C4Director(config[CONF_HOST], director_token_dict[CONF_TOKEN],
                          no_verify_ssl_session)

    _LOGGER.debug("Saving new account and director tokens in hass data")
    entry_data = hass.data[DOMAIN][entry.entry_id]
    entry_data[CONF_ACCOUNT] = account
    entry_data[CONF_DIRECTOR] = director

    if not (CONF_WEBSOCKET in entry_data
            and isinstance(entry_data[CONF_WEBSOCKET], C4Websocket)):
        _LOGGER.debug("First time setup, creating new C4Websocket object")
        connection_tracker = C4WebsocketConnectionTracker(hass, entry)
        websocket = C4Websocket(
            config[CONF_HOST],
            no_verify_ssl_session,
            connection_tracker.connect_callback,
            connection_tracker.disconnect_callback,
        )
        entry_data[CONF_WEBSOCKET] = websocket

        # Silence C4Websocket related loggers, that would otherwise spam INFO logs with debugging messages
        logging.getLogger("socketio.client").setLevel(logging.WARNING)
        logging.getLogger("engineio.client").setLevel(logging.WARNING)
        logging.getLogger("charset_normalizer").setLevel(logging.ERROR)

    _LOGGER.debug("Starting new WebSocket connection")
    await entry_data[CONF_WEBSOCKET].sio_connect(director.director_bearer_token
                                                 )

    _LOGGER.debug(
        "Registering next token refresh in %s seconds",
        director_token_dict["validSeconds"],
    )
    obj = RefreshTokensObject(hass, entry)
    entry_data[CONF_CANCEL_TOKEN_REFRESH_CALLBACK] = async_call_later(
        hass=hass,
        delay=director_token_dict["validSeconds"],
        action=obj.refresh_tokens,
    )