Пример #1
0
def async_setup(hass, config):
    """Initialize the DuckDNS component."""
    domain = config[DOMAIN][CONF_DOMAIN]
    token = config[DOMAIN][CONF_ACCESS_TOKEN]
    session = async_get_clientsession(hass)

    result = yield from _update_duckdns(session, domain, token)

    if not result:
        return False

    @asyncio.coroutine
    def update_domain_interval(now):
        """Update the DuckDNS entry."""
        yield from _update_duckdns(session, domain, token)

    @asyncio.coroutine
    def update_domain_service(call):
        """Update the DuckDNS entry."""
        yield from _update_duckdns(session, domain, token,
                                   txt=call.data[ATTR_TXT])

    async_track_time_interval(hass, update_domain_interval, INTERVAL)
    hass.services.async_register(
        DOMAIN, SERVICE_SET_TXT, update_domain_service,
        schema=SERVICE_TXT_SCHEMA)

    return result
Пример #2
0
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Set up the scenes stored in the LIFX Cloud."""
    token = config.get(CONF_TOKEN)
    timeout = config.get(CONF_TIMEOUT)

    headers = {
        AUTHORIZATION: "Bearer {}".format(token),
    }

    url = LIFX_API_URL.format('scenes')

    try:
        httpsession = async_get_clientsession(hass)
        with async_timeout.timeout(timeout, loop=hass.loop):
            scenes_resp = yield from httpsession.get(url, headers=headers)

    except (asyncio.TimeoutError, aiohttp.ClientError):
        _LOGGER.exception("Error on %s", url)
        return False

    status = scenes_resp.status
    if status == 200:
        data = yield from scenes_resp.json()
        devices = []
        for scene in data:
            devices.append(LifxCloudScene(hass, headers, timeout, scene))
        async_add_devices(devices)
        return True
    elif status == 401:
        _LOGGER.error("Unauthorized (bad token?) on %s", url)
        return False

    _LOGGER.error("HTTP error %d on %s", scenes_resp.status, url)
    return False
Пример #3
0
    async def async_camera_image(self):
        """Return a still image response from the camera."""
        # DigestAuth is not supported
        if self._authentication == HTTP_DIGEST_AUTHENTICATION or \
           self._still_image_url is None:
            image = await self.hass.async_add_job(
                self.camera_image)
            return image

        websession = async_get_clientsession(
            self.hass,
            verify_ssl=self._verify_ssl
        )
        try:
            with async_timeout.timeout(10, loop=self.hass.loop):
                response = await websession.get(
                    self._still_image_url, auth=self._auth)

                image = await response.read()
                return image

        except asyncio.TimeoutError:
            _LOGGER.error("Timeout getting camera image")

        except aiohttp.ClientError as err:
            _LOGGER.error("Error getting new camera image: %s", err)
Пример #4
0
async def get_bridge(hass, host, username=None):
    """Create a bridge object and verify authentication."""
    import aiohue

    bridge = aiohue.Bridge(
        host, username=username,
        websession=aiohttp_client.async_get_clientsession(hass)
    )

    try:
        with async_timeout.timeout(5):
            # Create username if we don't have one
            if not username:
                await bridge.create_user('home-assistant')
            # Initialize bridge (and validate our username)
            await bridge.initialize()

        return bridge
    except (aiohue.LinkButtonNotPressed, aiohue.Unauthorized):
        LOGGER.warning("Connected to Hue at %s but not registered.", host)
        raise AuthenticationRequired
    except (asyncio.TimeoutError, aiohue.RequestError):
        LOGGER.error("Error connecting to the Hue bridge at %s", host)
        raise CannotConnect
    except aiohue.AiohueException:
        LOGGER.exception('Unknown Hue linking error occurred')
        raise AuthenticationRequired
Пример #5
0
    async def handle_async_mjpeg_stream(self, request):
        """Return an MJPEG stream."""
        # The snapshot implementation is handled by the parent class
        if self._stream_source == STREAM_SOURCE_LIST['snapshot']:
            return await super().handle_async_mjpeg_stream(request)

        if self._stream_source == STREAM_SOURCE_LIST['mjpeg']:
            # stream an MJPEG image stream directly from the camera
            websession = async_get_clientsession(self.hass)
            streaming_url = self._camera.mjpeg_url(typeno=self._resolution)
            stream_coro = websession.get(
                streaming_url, auth=self._token, timeout=TIMEOUT)

            return await async_aiohttp_proxy_web(
                self.hass, request, stream_coro)

        # streaming via ffmpeg
        from haffmpeg import CameraMjpeg

        streaming_url = self._camera.rtsp_url(typeno=self._resolution)
        stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
        await stream.open_camera(
            streaming_url, extra_cmd=self._ffmpeg_arguments)

        try:
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream,
                'multipart/x-mixed-replace;boundary=ffserver')
        finally:
            await stream.close()
Пример #6
0
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Set up the RESTful switch."""
    name = config.get(CONF_NAME)
    resource = config.get(CONF_RESOURCE)
    body_on = config.get(CONF_BODY_ON)
    body_off = config.get(CONF_BODY_OFF)
    is_on_template = config.get(CONF_IS_ON_TEMPLATE)
    websession = async_get_clientsession(hass)

    if is_on_template is not None:
        is_on_template.hass = hass
    if body_on is not None:
        body_on.hass = hass
    if body_off is not None:
        body_off.hass = hass
    timeout = config.get(CONF_TIMEOUT)

    req = None
    try:
        with async_timeout.timeout(timeout, loop=hass.loop):
            req = yield from websession.get(resource)
    except (TypeError, ValueError):
        _LOGGER.error("Missing resource or schema in configuration. "
                      "Add http:// or https:// to your URL")
        return False
    except (asyncio.TimeoutError, aiohttp.errors.ClientError):
        _LOGGER.error("No route to resource/endpoint: %s", resource)
        return False
    finally:
        if req is not None:
            yield from req.release()

    yield from async_add_devices(
        [RestSwitch(hass, name, resource, body_on, body_off,
                    is_on_template, timeout)])
Пример #7
0
    def async_update(self):
        """Get the latest data from REST API and update the state."""
        websession = async_get_clientsession(self.hass)

        request = None
        try:
            with async_timeout.timeout(self._timeout, loop=self.hass.loop):
                request = yield from websession.get(self._resource)
                text = yield from request.text()
        except (asyncio.TimeoutError, aiohttp.errors.ClientError):
            _LOGGER.exception("Error while fetch data.")
            return
        finally:
            if request is not None:
                yield from request.release()

        if self._is_on_template is not None:
            text = self._is_on_template.async_render_with_possible_json_value(
                text, 'None')
            text = text.lower()
            if text == 'true':
                self._state = True
            elif text == 'false':
                self._state = False
            else:
                self._state = None
        else:
            if text == self._body_on.template:
                self._state = True
            elif text == self._body_off.template:
                self._state = False
            else:
                self._state = None
Пример #8
0
async def async_setup_platform(hass, config, async_add_entities,
                               discovery_info=None):
    """Set up the devices associated with the account."""
    from foobot_async import FoobotClient

    token = config.get(CONF_TOKEN)
    username = config.get(CONF_USERNAME)

    client = FoobotClient(token, username,
                          async_get_clientsession(hass),
                          timeout=TIMEOUT)
    dev = []
    try:
        devices = await client.get_devices()
        _LOGGER.debug("The following devices were found: %s", devices)
        for device in devices:
            foobot_data = FoobotData(client, device['uuid'])
            for sensor_type in SENSOR_TYPES:
                if sensor_type == 'time':
                    continue
                foobot_sensor = FoobotSensor(foobot_data, device, sensor_type)
                dev.append(foobot_sensor)
    except (aiohttp.client_exceptions.ClientConnectorError,
            asyncio.TimeoutError, FoobotClient.TooManyRequests,
            FoobotClient.InternalError):
        _LOGGER.exception('Failed to connect to foobot servers.')
        raise PlatformNotReady
    except FoobotClient.ClientError:
        _LOGGER.error('Failed to fetch data from foobot servers.')
        return
    async_add_entities(dev, True)
Пример #9
0
async def async_setup_platform(
        hass, config, async_add_entities, discovery_info=None):
    """Set up the Luftdaten sensor."""
    from luftdaten import Luftdaten

    name = config.get(CONF_NAME)
    show_on_map = config.get(CONF_SHOW_ON_MAP)
    sensor_id = config.get(CONF_SENSORID)

    session = async_get_clientsession(hass)
    luftdaten = LuftdatenData(Luftdaten(sensor_id, hass.loop, session))

    await luftdaten.async_update()

    if luftdaten.data is None:
        _LOGGER.error("Sensor is not available: %s", sensor_id)
        return

    devices = []
    for variable in config[CONF_MONITORED_CONDITIONS]:
        if luftdaten.data.values[variable] is None:
            _LOGGER.warning("It might be that sensor %s is not providing "
                            "measurements for %s", sensor_id, variable)
        devices.append(
            LuftdatenSensor(luftdaten, name, variable, sensor_id, show_on_map))

    async_add_entities(devices)
Пример #10
0
    def send_volumio_msg(self, method, params=None):
        """Send message."""
        url = "http://{}:{}/api/v1/{}/".format(self.host, self.port, method)

        _LOGGER.debug("URL: %s params: %s", url, params)

        try:
            websession = async_get_clientsession(self.hass)
            response = yield from websession.get(url, params=params)
            if response.status == 200:
                data = yield from response.json()
            else:
                _LOGGER.error(
                    "Query failed, response code: %s Full message: %s",
                    response.status, response)
                return False

        except (asyncio.TimeoutError, aiohttp.ClientError) as error:
            _LOGGER.error("Failed communicating with Volumio: %s", type(error))
            return False

        try:
            return data
        except AttributeError:
            _LOGGER.error("Received invalid response: %s", data)
            return False
Пример #11
0
    def async_update(self):
        """Get the current state from The Things Network Data Storage."""
        try:
            session = async_get_clientsession(self._hass)
            with async_timeout.timeout(DEFAULT_TIMEOUT, loop=self._hass.loop):
                req = yield from session.get(self._url, headers=self._headers)

        except (asyncio.TimeoutError, aiohttp.ClientError):
            _LOGGER.error("Error while accessing: %s", self._url)
            return False

        status = req.status

        if status == 204:
            _LOGGER.error("The device is not available: %s", self._device_id)
            return False

        if status == 401:
            _LOGGER.error(
                "Not authorized for Application ID: %s", self._app_id)
            return False

        if status == 404:
            _LOGGER.error("Application ID is not available: %s", self._app_id)
            return False

        data = yield from req.json()
        self.data = data[0]

        for value in self._values.items():
            if value[0] not in self.data.keys():
                _LOGGER.warning("Value not available: %s", value[0])

        return req
Пример #12
0
    def async_get_tts_audio(self, message, language, options=None):
        """Load TTS from yandex."""
        websession = async_get_clientsession(self.hass)
        actual_language = language

        try:
            with async_timeout.timeout(10, loop=self.hass.loop):
                url_param = {
                    'text': message,
                    'lang': actual_language,
                    'key': self._key,
                    'speaker': self._speaker,
                    'format': self._codec,
                    'emotion': self._emotion,
                    'speed': self._speed
                }

                request = yield from websession.get(
                    YANDEX_API_URL, params=url_param)

                if request.status != 200:
                    _LOGGER.error("Error %d on load URL %s",
                                  request.status, request.url)
                    return (None, None)
                data = yield from request.read()

        except (asyncio.TimeoutError, aiohttp.ClientError):
            _LOGGER.error("Timeout for yandex speech kit API")
            return (None, None)

        return (self._codec, data)
Пример #13
0
async def get_service(hass, config, discovery_info=None):
    """Get the Flock notification service."""
    access_token = config.get(CONF_ACCESS_TOKEN)
    url = '{}{}'.format(_RESOURCE, access_token)
    session = async_get_clientsession(hass)

    return FlockNotificationService(url, session, hass.loop)
Пример #14
0
async def async_setup_platform(
        hass, config, async_add_entities, discovery_info=None):
    """Set up the Glances sensors."""
    from glances_api import Glances

    name = config[CONF_NAME]
    host = config[CONF_HOST]
    port = config[CONF_PORT]
    version = config[CONF_VERSION]
    var_conf = config[CONF_RESOURCES]
    username = config.get(CONF_USERNAME)
    password = config.get(CONF_PASSWORD)
    ssl = config[CONF_SSL]
    verify_ssl = config[CONF_VERIFY_SSL]

    session = async_get_clientsession(hass, verify_ssl)
    glances = GlancesData(
        Glances(hass.loop, session, host=host, port=port, version=version,
                username=username, password=password, ssl=ssl))

    await glances.async_update()

    if glances.api.data is None:
        raise PlatformNotReady

    dev = []
    for resource in var_conf:
        dev.append(GlancesSensor(glances, name, resource))

    async_add_entities(dev, True)
Пример #15
0
def _setup_atv(hass, atv_config):
    """Setup an Apple TV."""
    import pyatv
    name = atv_config.get(CONF_NAME)
    host = atv_config.get(CONF_HOST)
    login_id = atv_config.get(CONF_LOGIN_ID)
    start_off = atv_config.get(CONF_START_OFF)
    credentials = atv_config.get(CONF_CREDENTIALS)

    if host in hass.data[DATA_APPLE_TV]:
        return

    details = pyatv.AppleTVDevice(name, host, login_id)
    session = async_get_clientsession(hass)
    atv = pyatv.connect_to_apple_tv(details, hass.loop, session=session)
    if credentials:
        yield from atv.airplay.load_credentials(credentials)

    power = AppleTVPowerManager(hass, atv, start_off)
    hass.data[DATA_APPLE_TV][host] = {
        ATTR_ATV: atv,
        ATTR_POWER: power
    }

    hass.async_add_job(discovery.async_load_platform(
        hass, 'media_player', DOMAIN, atv_config))

    hass.async_add_job(discovery.async_load_platform(
        hass, 'remote', DOMAIN, atv_config))
Пример #16
0
    def __init__(self, hass, host, port=None, name=None, init_callback=None):
        """Initialize the media player."""
        self.host = host
        self._hass = hass
        self.port = port
        self._polling_session = async_get_clientsession(hass)
        self._polling_task = None  # The actual polling task.
        self._name = name
        self._icon = None
        self._capture_items = []
        self._services_items = []
        self._preset_items = []
        self._sync_status = {}
        self._status = None
        self._last_status_update = None
        self._is_online = False
        self._retry_remove = None
        self._lastvol = None
        self._master = None
        self._is_master = False
        self._group_name = None

        self._init_callback = init_callback
        if self.port is None:
            self.port = DEFAULT_PORT
Пример #17
0
def get_newest_version(hass, huuid, include_components):
    """Get the newest Home Assistant version."""
    if huuid:
        info_object = yield from get_system_info(hass, include_components)
        info_object['huuid'] = huuid
    else:
        info_object = {}

    session = async_get_clientsession(hass)
    try:
        with async_timeout.timeout(5, loop=hass.loop):
            req = yield from session.post(UPDATER_URL, json=info_object)
        _LOGGER.info(("Submitted analytics to Home Assistant servers. "
                      "Information submitted includes %s"), info_object)
    except (asyncio.TimeoutError, aiohttp.ClientError):
        _LOGGER.error("Could not contact Home Assistant Update to check "
                      "for updates")
        return None

    try:
        res = yield from req.json()
    except ValueError:
        _LOGGER.error("Received invalid JSON from Home Assistant Update")
        return None

    try:
        res = RESPONSE_SCHEMA(res)
        return res['version'], res['release-notes']
    except vol.Invalid:
        _LOGGER.error("Got unexpected response: %s", res)
        return None
Пример #18
0
    async def fetching_data(self, *_):
        """Get the latest data from yr.no."""
        import xmltodict

        def try_again(err: str):
            """Retry in 15 to 20 minutes."""
            minutes = 15 + randrange(6)
            _LOGGER.error("Retrying in %i minutes: %s", minutes, err)
            async_call_later(self.hass, minutes*60, self.fetching_data)
        try:
            websession = async_get_clientsession(self.hass)
            with async_timeout.timeout(10, loop=self.hass.loop):
                resp = await websession.get(
                    self._url, params=self._urlparams)
            if resp.status != 200:
                try_again('{} returned {}'.format(resp.url, resp.status))
                return
            text = await resp.text()

        except (asyncio.TimeoutError, aiohttp.ClientError) as err:
            try_again(err)
            return

        try:
            self.data = xmltodict.parse(text)['weatherdata']
        except (ExpatError, IndexError) as err:
            try_again(err)
            return

        await self.updating_devices()
        async_call_later(self.hass, 60*60, self.fetching_data)
Пример #19
0
async def async_setup_platform(
        hass, config, async_add_entities, discovery_info=None):
    """Set up the Netdata sensor."""
    from netdata import Netdata

    name = config.get(CONF_NAME)
    host = config.get(CONF_HOST)
    port = config.get(CONF_PORT)
    resources = config.get(CONF_RESOURCES)

    session = async_get_clientsession(hass)
    netdata = NetdataData(Netdata(host, hass.loop, session, port=port))
    await netdata.async_update()

    if netdata.api.metrics is None:
        raise PlatformNotReady

    dev = []
    for entry, data in resources.items():
        icon = data[CONF_ICON]
        sensor = data[CONF_DATA_GROUP]
        element = data[CONF_ELEMENT]
        sensor_name = entry
        try:
            resource_data = netdata.api.metrics[sensor]
            unit = '%' if resource_data['units'] == 'percentage' else \
                resource_data['units']
        except KeyError:
            _LOGGER.error("Sensor is not available: %s", sensor)
            continue

        dev.append(NetdataSensor(
            netdata, name, sensor, sensor_name, element, icon, unit))

    async_add_entities(dev, True)
Пример #20
0
    async def get_device_state(self, hass):
        """Get the latest data from REST API and update the state."""
        websession = async_get_clientsession(hass)

        with async_timeout.timeout(self._timeout, loop=hass.loop):
            req = await websession.get(self._resource, auth=self._auth,
                                       headers=self._headers)
            text = await req.text()

        if self._is_on_template is not None:
            text = self._is_on_template.async_render_with_possible_json_value(
                text, 'None')
            text = text.lower()
            if text == 'true':
                self._state = True
            elif text == 'false':
                self._state = False
            else:
                self._state = None
        else:
            if text == self._body_on.template:
                self._state = True
            elif text == self._body_off.template:
                self._state = False
            else:
                self._state = None

        return req
Пример #21
0
async def async_setup_platform(hass, config, async_add_entities,
                               discovery_info=None):
    """Set up the Mill heater."""
    from mill import Mill
    mill_data_connection = Mill(config[CONF_USERNAME],
                                config[CONF_PASSWORD],
                                websession=async_get_clientsession(hass))
    if not await mill_data_connection.connect():
        _LOGGER.error("Failed to connect to Mill")
        return

    await mill_data_connection.find_all_heaters()

    dev = []
    for heater in mill_data_connection.heaters.values():
        dev.append(MillHeater(heater, mill_data_connection))
    async_add_entities(dev)

    async def set_room_temp(service):
        """Set room temp."""
        room_name = service.data.get(ATTR_ROOM_NAME)
        sleep_temp = service.data.get(ATTR_SLEEP_TEMP)
        comfort_temp = service.data.get(ATTR_COMFORT_TEMP)
        away_temp = service.data.get(ATTR_AWAY_TEMP)
        await mill_data_connection.set_room_temperatures_by_name(room_name,
                                                                 sleep_temp,
                                                                 comfort_temp,
                                                                 away_temp)

    hass.services.async_register(DOMAIN, SERVICE_SET_ROOM_TEMP,
                                 set_room_temp, schema=SET_ROOM_TEMP_SCHEMA)
Пример #22
0
    async def async_step_user(self, user_input=None):
        """Handle the start of the config flow."""
        from aioambient import Client
        from aioambient.errors import AmbientError

        if not user_input:
            return await self._show_form()

        if user_input[CONF_APP_KEY] in configured_instances(self.hass):
            return await self._show_form({CONF_APP_KEY: 'identifier_exists'})

        session = aiohttp_client.async_get_clientsession(self.hass)
        client = Client(
            user_input[CONF_API_KEY], user_input[CONF_APP_KEY], session)

        try:
            devices = await client.api.get_devices()
        except AmbientError:
            return await self._show_form({'base': 'invalid_key'})

        if not devices:
            return await self._show_form({'base': 'no_devices'})

        # The Application Key (which identifies each config entry) is too long
        # to show nicely in the UI, so we take the first 12 characters (similar
        # to how GitHub does it):
        return self.async_create_entry(
            title=user_input[CONF_APP_KEY][:12], data=user_input)
Пример #23
0
    def async_get_tts_audio(self, message):
        """Load TTS from voicerss."""
        websession = async_get_clientsession(self.hass)
        form_data = self.form_data.copy()

        form_data['src'] = message

        request = None
        try:
            with async_timeout.timeout(10, loop=self.hass.loop):
                request = yield from websession.post(
                    VOICERSS_API_URL, data=form_data
                )

                if request.status != 200:
                    _LOGGER.error("Error %d on load url %s.",
                                  request.status, request.url)
                    return (None, None)
                data = yield from request.read()

                if data in ERROR_MSG:
                    _LOGGER.error(
                        "Error receive %s from voicerss.", str(data, 'utf-8'))
                    return (None, None)

        except (asyncio.TimeoutError, aiohttp.errors.ClientError):
            _LOGGER.error("Timeout for voicerss api.")
            return (None, None)

        finally:
            if request is not None:
                yield from request.release()

        return (self.extension, data)
Пример #24
0
    async def handle_async_mjpeg_stream(self, request):
        """Return an MJPEG stream."""
        # The snapshot implementation is handled by the parent class
        if self._stream_source == 'snapshot':
            return await super().handle_async_mjpeg_stream(request)

        if self._stream_source == 'mjpeg':
            # stream an MJPEG image stream directly from the camera
            websession = async_get_clientsession(self.hass)
            streaming_url = self._api.mjpeg_url(typeno=self._resolution)
            stream_coro = websession.get(
                streaming_url, auth=self._token,
                timeout=CAMERA_WEB_SESSION_TIMEOUT)

            return await async_aiohttp_proxy_web(
                self.hass, request, stream_coro)

        # streaming via ffmpeg
        from haffmpeg.camera import CameraMjpeg

        streaming_url = self._api.rtsp_url(typeno=self._resolution)
        stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
        await stream.open_camera(
            streaming_url, extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type)
        finally:
            await stream.close()
Пример #25
0
async def async_setup_entry(hass, config_entry):
    """Set up the Ambient PWS as config entry."""
    from aioambient import Client
    from aioambient.errors import WebsocketError

    session = aiohttp_client.async_get_clientsession(hass)

    try:
        ambient = AmbientStation(
            hass, config_entry,
            Client(
                config_entry.data[CONF_API_KEY],
                config_entry.data[CONF_APP_KEY], session),
            hass.data[DOMAIN].get(DATA_CONFIG, {}).get(
                CONF_MONITORED_CONDITIONS, []))
        hass.loop.create_task(ambient.ws_connect())
        hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = ambient
    except WebsocketError as err:
        _LOGGER.error('Config entry failed: %s', err)
        raise ConfigEntryNotReady

    hass.bus.async_listen_once(
        EVENT_HOMEASSISTANT_STOP, ambient.client.websocket.disconnect())

    return True
def async_setup_platform(hass, config, async_add_entities,
                         discovery_info=None):
    """Set up home assistant scene entries."""
    # from aiopvapi.hub import Hub
    from aiopvapi.scenes import Scenes
    from aiopvapi.rooms import Rooms
    from aiopvapi.resources.scene import Scene as PvScene

    hub_address = config.get(HUB_ADDRESS)
    websession = async_get_clientsession(hass)

    _scenes = yield from Scenes(
        hub_address, hass.loop, websession).get_resources()
    _rooms = yield from Rooms(
        hub_address, hass.loop, websession).get_resources()

    if not _scenes or not _rooms:
        _LOGGER.error(
            "Unable to initialize PowerView hub: %s", hub_address)
        return
    pvscenes = (PowerViewScene(hass,
                               PvScene(_raw_scene, hub_address, hass.loop,
                                       websession), _rooms)
                for _raw_scene in _scenes[SCENE_DATA])
    async_add_entities(pvscenes)
Пример #27
0
async def async_setup_platform(
        hass, config, async_add_devices, discovery_info=None):
    """Set up the Pi-hole sensor."""
    from hole import Hole

    name = config.get(CONF_NAME)
    host = config.get(CONF_HOST)
    use_tls = config.get(CONF_SSL)
    location = config.get(CONF_LOCATION)
    verify_tls = config.get(CONF_VERIFY_SSL)

    session = async_get_clientsession(hass)
    pi_hole = PiHoleData(Hole(
        host, hass.loop, session, location=location, tls=use_tls,
        verify_tls=verify_tls))

    await pi_hole.async_update()

    if pi_hole.api.data is None:
        raise PlatformNotReady

    sensors = [PiHoleSensor(pi_hole, name, condition)
               for condition in config[CONF_MONITORED_CONDITIONS]]

    async_add_devices(sensors, True)
Пример #28
0
    async def get_data(self, url):
        """Load data from specified url."""
        from buienradar.buienradar import (CONTENT,
                                           MESSAGE, STATUS_CODE, SUCCESS)

        _LOGGER.debug("Calling url: %s...", url)
        result = {SUCCESS: False, MESSAGE: None}
        resp = None
        try:
            websession = async_get_clientsession(self.hass)
            with async_timeout.timeout(10, loop=self.hass.loop):
                resp = await websession.get(url)

                result[STATUS_CODE] = resp.status
                result[CONTENT] = await resp.text()
                if resp.status == 200:
                    result[SUCCESS] = True
                else:
                    result[MESSAGE] = "Got http statuscode: %d" % (resp.status)

                return result
        except (asyncio.TimeoutError, aiohttp.ClientError) as err:
            result[MESSAGE] = "%s" % err
            return result
        finally:
            if resp is not None:
                await resp.release()
Пример #29
0
    def __init__(self, hass, name, host, port, tcp_port, encryption=False,
                 username=None, password=None, turn_off_action=None,
                 websocket=True):
        """Initialize the Kodi device."""
        import jsonrpc_async
        import jsonrpc_websocket
        self.hass = hass
        self._name = name

        kwargs = {
            'timeout': DEFAULT_TIMEOUT,
            'session': async_get_clientsession(hass),
        }

        if username is not None:
            kwargs['auth'] = aiohttp.BasicAuth(username, password)
            image_auth_string = "{}:{}@".format(username, password)
        else:
            image_auth_string = ""

        http_protocol = 'https' if encryption else 'http'
        ws_protocol = 'wss' if encryption else 'ws'

        self._http_url = '{}://{}:{}/jsonrpc'.format(http_protocol, host, port)
        self._image_url = '{}://{}{}:{}/image'.format(
            http_protocol, image_auth_string, host, port)
        self._ws_url = '{}://{}:{}/jsonrpc'.format(ws_protocol, host, tcp_port)

        self._http_server = jsonrpc_async.Server(self._http_url, **kwargs)
        if websocket:
            # Setup websocket connection
            self._ws_server = jsonrpc_websocket.Server(self._ws_url, **kwargs)

            # Register notification listeners
            self._ws_server.Player.OnPause = self.async_on_speed_event
            self._ws_server.Player.OnPlay = self.async_on_speed_event
            self._ws_server.Player.OnSpeedChanged = self.async_on_speed_event
            self._ws_server.Player.OnStop = self.async_on_stop
            self._ws_server.Application.OnVolumeChanged = \
                self.async_on_volume_changed
            self._ws_server.System.OnQuit = self.async_on_quit
            self._ws_server.System.OnRestart = self.async_on_quit
            self._ws_server.System.OnSleep = self.async_on_quit

            def on_hass_stop(event):
                """Close websocket connection when hass stops."""
                self.hass.async_add_job(self._ws_server.close())

            self.hass.bus.async_listen_once(
                EVENT_HOMEASSISTANT_STOP, on_hass_stop)
        else:
            self._ws_server = None

        self._turn_off_action = turn_off_action
        self._enable_websocket = websocket
        self._players = list()
        self._properties = {}
        self._item = {}
        self._app_properties = {}
        self._ws_connected = False
Пример #30
0
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Setup the Apple TV platform."""
    import pyatv

    if discovery_info is not None:
        name = discovery_info['name']
        host = discovery_info['host']
        login_id = discovery_info['properties']['hG']
        start_off = False
    else:
        name = config.get(CONF_NAME)
        host = config.get(CONF_HOST)
        login_id = config.get(CONF_LOGIN_ID)
        start_off = config.get(CONF_START_OFF)

    if DATA_APPLE_TV not in hass.data:
        hass.data[DATA_APPLE_TV] = []

    if host in hass.data[DATA_APPLE_TV]:
        return False
    hass.data[DATA_APPLE_TV].append(host)

    details = pyatv.AppleTVDevice(name, host, login_id)
    session = async_get_clientsession(hass)
    atv = pyatv.connect_to_apple_tv(details, hass.loop, session=session)
    entity = AppleTvDevice(atv, name, start_off)

    @callback
    def on_hass_stop(event):
        """Stop push updates when hass stops."""
        atv.push_updater.stop()

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop)

    async_add_devices([entity])
Пример #31
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Plugwise Smiles from a config entry."""
    websession = async_get_clientsession(hass, verify_ssl=False)
    api = Smile(
        host=entry.data["host"], password=entry.data["password"], websession=websession
    )

    try:
        connected = await api.connect()

        if not connected:
            _LOGGER.error("Unable to connect to Smile")
            raise ConfigEntryNotReady

    except Smile.InvalidAuthentication:
        _LOGGER.error("Invalid Smile ID")
        return False

    except Smile.PlugwiseError:
        _LOGGER.error("Error while communicating to device")
        raise ConfigEntryNotReady

    except asyncio.TimeoutError:
        _LOGGER.error("Timeout while connecting to Smile")
        raise ConfigEntryNotReady

    if api.smile_type == "power":
        update_interval = timedelta(seconds=10)
    else:
        update_interval = timedelta(seconds=60)

    async def async_update_data():
        """Update data via API endpoint."""
        try:
            async with async_timeout.timeout(10):
                await api.full_update_device()
                return True
        except Smile.XMLDataMissingError:
            raise UpdateFailed("Smile update failed")

    coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name="Smile",
        update_method=async_update_data,
        update_interval=update_interval,
    )

    await coordinator.async_refresh()

    if not coordinator.last_update_success:
        raise ConfigEntryNotReady

    api.get_all_devices()

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

    device_registry = await dr.async_get_registry(hass)
    device_registry.async_get_or_create(
        config_entry_id=entry.entry_id,
        identifiers={(DOMAIN, api.gateway_id)},
        manufacturer="Plugwise",
        name=entry.title,
        model=f"Smile {api.smile_name}",
        sw_version=api.smile_version[0],
    )

    platforms = ALL_PLATFORMS

    single_master_thermostat = api.single_master_thermostat()
    if single_master_thermostat is None:
        platforms = SENSOR_PLATFORMS

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

    return True
Пример #32
0
def async_setup_scanner(hass, config, async_see, discovery_info=None):
    """Validate the configuration and return an Automatic scanner."""
    import aioautomatic

    hass.http.register_view(AutomaticAuthCallbackView())

    scope = FULL_SCOPE if config.get(CONF_CURRENT_LOCATION) else DEFAULT_SCOPE

    client = aioautomatic.Client(
        client_id=config[CONF_CLIENT_ID],
        client_secret=config[CONF_SECRET],
        client_session=async_get_clientsession(hass),
        request_kwargs={"timeout": DEFAULT_TIMEOUT},
    )

    filename = AUTOMATIC_CONFIG_FILE.format(config[CONF_CLIENT_ID])
    refresh_token = yield from hass.async_add_job(_get_refresh_token_from_file,
                                                  hass, filename)

    @asyncio.coroutine
    def initialize_data(session):
        """Initialize the AutomaticData object from the created session."""
        hass.async_add_job(_write_refresh_token_to_file, hass, filename,
                           session.refresh_token)
        data = AutomaticData(hass, client, session, config.get(CONF_DEVICES),
                             async_see)

        # Load the initial vehicle data
        vehicles = yield from session.get_vehicles()
        for vehicle in vehicles:
            hass.async_create_task(data.load_vehicle(vehicle))

        # Create a task instead of adding a tracking job, since this task will
        # run until the websocket connection is closed.
        hass.loop.create_task(data.ws_connect())

    if refresh_token is not None:
        try:
            session = yield from client.create_session_from_refresh_token(
                refresh_token)
            yield from initialize_data(session)
            return True
        except aioautomatic.exceptions.AutomaticError as err:
            _LOGGER.error(str(err))

    configurator = hass.components.configurator
    request_id = configurator.async_request_config(
        "Automatic",
        description=("Authorization required for Automatic device tracker."),
        link_name="Click here to authorize Home Assistant.",
        link_url=client.generate_oauth_url(scope),
        entity_picture="/static/images/logo_automatic.png",
    )

    @asyncio.coroutine
    def initialize_callback(code, state):
        """Call after OAuth2 response is returned."""
        try:
            session = yield from client.create_session_from_oauth_code(
                code, state)
            yield from initialize_data(session)
            configurator.async_request_done(request_id)
        except aioautomatic.exceptions.AutomaticError as err:
            _LOGGER.error(str(err))
            configurator.async_notify_errors(request_id, str(err))
            return False

    if DATA_CONFIGURING not in hass.data:
        hass.data[DATA_CONFIGURING] = {}

    hass.data[DATA_CONFIGURING][client.state] = initialize_callback
    return True
Пример #33
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up AirVisual as config entry."""
    if CONF_API_KEY in entry.data:
        _standardize_geography_config_entry(hass, entry)

        websession = aiohttp_client.async_get_clientsession(hass)
        cloud_api = CloudAPI(entry.data[CONF_API_KEY], session=websession)

        async def async_update_data() -> dict[str, Any]:
            """Get new data from the API."""
            if CONF_CITY in entry.data:
                api_coro = cloud_api.air_quality.city(
                    entry.data[CONF_CITY],
                    entry.data[CONF_STATE],
                    entry.data[CONF_COUNTRY],
                )
            else:
                api_coro = cloud_api.air_quality.nearest_city(
                    entry.data[CONF_LATITUDE],
                    entry.data[CONF_LONGITUDE],
                )

            try:
                data = await api_coro
                return cast(Dict[str, Any], data)
            except (InvalidKeyError, KeyExpiredError) as ex:
                raise ConfigEntryAuthFailed from ex
            except AirVisualError as err:
                raise UpdateFailed(
                    f"Error while retrieving data: {err}") from err

        coordinator = DataUpdateCoordinator(
            hass,
            LOGGER,
            name=async_get_geography_id(entry.data),
            # We give a placeholder update interval in order to create the coordinator;
            # then, below, we use the coordinator's presence (along with any other
            # coordinators using the same API key) to calculate an actual, leveled
            # update interval:
            update_interval=timedelta(minutes=5),
            update_method=async_update_data,
        )

        # Only geography-based entries have options:
        entry.async_on_unload(entry.add_update_listener(async_reload_entry))
    else:
        # Remove outdated air_quality entities from the entity registry if they exist:
        ent_reg = entity_registry.async_get(hass)
        for entity_entry in [
                e for e in ent_reg.entities.values()
                if e.config_entry_id == entry.entry_id
                and e.entity_id.startswith("air_quality")
        ]:
            LOGGER.debug('Removing deprecated air_quality entity: "%s"',
                         entity_entry.entity_id)
            ent_reg.async_remove(entity_entry.entity_id)

        _standardize_node_pro_config_entry(hass, entry)

        async def async_update_data() -> dict[str, Any]:
            """Get new data from the API."""
            try:
                async with NodeSamba(entry.data[CONF_IP_ADDRESS],
                                     entry.data[CONF_PASSWORD]) as node:
                    data = await node.async_get_latest_measurements()
                    return cast(Dict[str, Any], data)
            except NodeProError as err:
                raise UpdateFailed(
                    f"Error while retrieving data: {err}") from err

        coordinator = DataUpdateCoordinator(
            hass,
            LOGGER,
            name="Node/Pro data",
            update_interval=DEFAULT_NODE_PRO_UPDATE_INTERVAL,
            update_method=async_update_data,
        )

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

    # Reassess the interval between 2 server requests
    if CONF_API_KEY in entry.data:
        async_sync_geo_coordinator_update_intervals(hass,
                                                    entry.data[CONF_API_KEY])

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Пример #34
0
async def async_setup_entry_gw(hass: HomeAssistant,
                               entry: ConfigEntry) -> bool:
    """Set up Plugwise Smiles from a config entry."""
    websession = async_get_clientsession(hass, verify_ssl=False)

    api = Smile(
        host=entry.data[CONF_HOST],
        username=entry.data.get(CONF_USERNAME, DEFAULT_USERNAME),
        password=entry.data[CONF_PASSWORD],
        port=entry.data.get(CONF_PORT, DEFAULT_PORT),
        timeout=30,
        websession=websession,
    )

    try:
        connected = await api.connect()

        if not connected:
            _LOGGER.error("Unable to connect to Smile")
            raise ConfigEntryNotReady

    except InvalidAuthentication:
        _LOGGER.error("Invalid username or Smile ID")
        return False

    except PlugwiseException as err:
        _LOGGER.error("Error while communicating to device %s", api.smile_name)
        raise ConfigEntryNotReady from err

    except asyncio.TimeoutError as err:
        _LOGGER.error("Timeout while connecting to Smile %s", api.smile_name)
        raise ConfigEntryNotReady from err

    update_interval = timedelta(seconds=entry.options.get(
        CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL[api.smile_type]))

    async def async_update_data():
        """Update data via API endpoint."""
        try:
            async with async_timeout.timeout(DEFAULT_TIMEOUT):
                await api.full_update_device()
                return True
        except XMLDataMissingError as err:
            raise UpdateFailed("Smile update failed") from err

    coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name=f"Smile {api.smile_name}",
        update_method=async_update_data,
        update_interval=update_interval,
    )

    await coordinator.async_refresh()

    if not coordinator.last_update_success:
        raise ConfigEntryNotReady

    api.get_all_devices()

    if entry.unique_id is None:
        if api.smile_version[0] != "1.8.0":
            hass.config_entries.async_update_entry(
                entry, unique_id=api.smile_hostname)

    undo_listener = entry.add_update_listener(_update_listener)

    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
        "api": api,
        COORDINATOR: coordinator,
        PW_TYPE: GATEWAY,
        UNDO_UPDATE_LISTENER: undo_listener,
    }

    device_registry = await dr.async_get_registry(hass)
    device_registry.async_get_or_create(
        config_entry_id=entry.entry_id,
        identifiers={(DOMAIN, api.gateway_id)},
        manufacturer="Plugwise",
        name=entry.title,
        model=f"Smile {api.smile_name}",
        sw_version=api.smile_version[0],
    )

    single_master_thermostat = api.single_master_thermostat()

    platforms = PLATFORMS_GATEWAY
    if single_master_thermostat is None:
        platforms = SENSOR_PLATFORMS

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

    return True
Пример #35
0
async def async_setup_entry(hass, entry):
    """Set up Plex from a config entry."""
    server_config = entry.data[PLEX_SERVER_CONFIG]

    if entry.unique_id is None:
        hass.config_entries.async_update_entry(
            entry, unique_id=entry.data[CONF_SERVER_IDENTIFIER])

    if MP_DOMAIN not in entry.options:
        options = dict(entry.options)
        options.setdefault(MP_DOMAIN, {})
        hass.config_entries.async_update_entry(entry, options=options)

    plex_server = PlexServer(
        hass,
        server_config,
        entry.data[CONF_SERVER_IDENTIFIER],
        entry.options,
        entry.entry_id,
    )
    try:
        await hass.async_add_executor_job(plex_server.connect)
    except ShouldUpdateConfigEntry:
        new_server_data = {
            **entry.data[PLEX_SERVER_CONFIG],
            CONF_URL: plex_server.url_in_use,
            CONF_SERVER: plex_server.friendly_name,
        }
        hass.config_entries.async_update_entry(
            entry, data={
                **entry.data, PLEX_SERVER_CONFIG: new_server_data
            })
    except requests.exceptions.ConnectionError as error:
        if entry.state != ENTRY_STATE_SETUP_RETRY:
            _LOGGER.error(
                "Plex server (%s) could not be reached: [%s]",
                server_config[CONF_URL],
                error,
            )
        raise ConfigEntryNotReady from error
    except plexapi.exceptions.Unauthorized:
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                PLEX_DOMAIN,
                context={CONF_SOURCE: SOURCE_REAUTH},
                data=entry.data,
            ))
        _LOGGER.error(
            "Token not accepted, please reauthenticate Plex server '%s'",
            entry.data[CONF_SERVER],
        )
        return False
    except (
            plexapi.exceptions.BadRequest,
            plexapi.exceptions.NotFound,
    ) as error:
        _LOGGER.error(
            "Login to %s failed, verify token and SSL settings: [%s]",
            entry.data[CONF_SERVER],
            error,
        )
        return False

    _LOGGER.debug("Connected to: %s (%s)", plex_server.friendly_name,
                  plex_server.url_in_use)
    server_id = plex_server.machine_identifier
    hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
    hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] = set()

    entry.add_update_listener(async_options_updated)

    unsub = async_dispatcher_connect(
        hass,
        PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
        plex_server.async_update_platforms,
    )
    hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    @callback
    def plex_websocket_callback(msgtype, data, error):
        """Handle callbacks from plexwebsocket library."""
        if msgtype == SIGNAL_CONNECTION_STATE:

            if data == STATE_CONNECTED:
                _LOGGER.debug("Websocket to %s successful",
                              entry.data[CONF_SERVER])
                hass.async_create_task(plex_server.async_update_platforms())
            elif data == STATE_DISCONNECTED:
                _LOGGER.debug("Websocket to %s disconnected, retrying",
                              entry.data[CONF_SERVER])
            # Stopped websockets without errors are expected during shutdown and ignored
            elif data == STATE_STOPPED and error:
                _LOGGER.error(
                    "Websocket to %s failed, aborting [Error: %s]",
                    entry.data[CONF_SERVER],
                    error,
                )
                hass.async_create_task(
                    hass.config_entries.async_reload(entry.entry_id))

        elif msgtype == "playing":
            hass.async_create_task(plex_server.async_update_session(data))
        elif msgtype == "status":
            if data["StatusNotification"][0][
                    "title"] == "Library scan complete":
                async_dispatcher_send(
                    hass,
                    PLEX_UPDATE_LIBRARY_SIGNAL.format(server_id),
                )

    session = async_get_clientsession(hass)
    subscriptions = ["playing", "status"]
    verify_ssl = server_config.get(CONF_VERIFY_SSL)
    websocket = PlexWebsocket(
        plex_server.plex_server,
        plex_websocket_callback,
        subscriptions=subscriptions,
        session=session,
        verify_ssl=verify_ssl,
    )
    hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket

    def start_websocket_session(platform, _):
        hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id].add(platform)
        if hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] == PLATFORMS:
            hass.loop.create_task(websocket.listen())

    def close_websocket_session(_):
        websocket.close()

    unsub = hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       close_websocket_session)
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    for platform in PLATFORMS:
        task = hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, platform))
        task.add_done_callback(partial(start_websocket_session, platform))

    async_cleanup_plex_devices(hass, entry)

    def get_plex_account(plex_server):
        try:
            return plex_server.account
        except (plexapi.exceptions.BadRequest,
                plexapi.exceptions.Unauthorized):
            return None

    await hass.async_add_executor_job(get_plex_account, plex_server)

    return True
Пример #36
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
Пример #37
0
    async def async_connect(self):
        """Connect to remote home-assistant websocket..."""
        async def _async_stop_handler(event):
            """Stop when Home Assistant is shutting down."""
            await self.async_stop()

        async def _async_instance_get_info():
            """Fetch discovery info from remote instance."""
            try:
                return await async_get_discovery_info(
                    self._hass,
                    self._entry.data[CONF_HOST],
                    self._entry.data[CONF_PORT],
                    self._secure,
                    self._access_token,
                    self._verify_ssl,
                )
            except OSError:
                _LOGGER.exception("failed to connect")
            except UnsupportedVersion:
                _LOGGER.error(
                    "Unsupported version, at least 0.111 is required.")
            except Exception:
                _LOGGER.exception("failed to fetch instance info")
            return None

        @callback
        def _async_instance_id_match(info):
            """Verify if remote instance id matches the expected id."""
            if not info:
                return False
            if info and info["uuid"] != self._entry.unique_id:
                _LOGGER.error(
                    "instance id not matching: %s != %s",
                    info["uuid"],
                    self._entry.unique_id,
                )
                return False
            return True

        url = self._get_url()

        session = async_get_clientsession(self._hass, self._verify_ssl)
        self.set_connection_state(STATE_CONNECTING)

        while True:
            info = await _async_instance_get_info()

            # Verify we are talking to correct instance
            if not _async_instance_id_match(info):
                self.set_connection_state(STATE_RECONNECTING)
                await asyncio.sleep(10)
                continue

            try:
                _LOGGER.info("Connecting to %s", url)
                self._connection = await session.ws_connect(url)
            except aiohttp.client_exceptions.ClientError:
                _LOGGER.error(
                    "Could not connect to %s, retry in 10 seconds...", url)
                self.set_connection_state(STATE_RECONNECTING)
                await asyncio.sleep(10)
            else:
                _LOGGER.info("Connected to home-assistant websocket at %s",
                             url)
                break

        self._hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                         _async_stop_handler)

        device_registry = await dr.async_get_registry(self._hass)
        device_registry.async_get_or_create(
            config_entry_id=self._entry.entry_id,
            identifiers={(DOMAIN, f"remote_{self._entry.unique_id}")},
            name=info.get("location_name"),
            manufacturer="Home Assistant",
            model=info.get("installation_type"),
            sw_version=info.get("version"),
        )

        asyncio.ensure_future(self._recv())
        self._heartbeat_task = self._hass.loop.create_task(
            self._heartbeat_loop())
Пример #38
0
    async def async_step_user(self, user_input=None):
        """Get access token and validate it."""
        errors = {}
        if user_input is None or CONF_ACCESS_TOKEN not in user_input:
            return self._show_step_user(errors)

        self.access_token = user_input.get(CONF_ACCESS_TOKEN, "")
        self.api = SmartThings(async_get_clientsession(self.hass), self.access_token)

        # Ensure token is a UUID
        if not VAL_UID_MATCHER.match(self.access_token):
            errors[CONF_ACCESS_TOKEN] = "token_invalid_format"
            return self._show_step_user(errors)
        # Check not already setup in another entry
        if any(
            entry.data.get(CONF_ACCESS_TOKEN) == self.access_token
            for entry in self.hass.config_entries.async_entries(DOMAIN)
        ):
            errors[CONF_ACCESS_TOKEN] = "token_already_setup"
            return self._show_step_user(errors)

        # Setup end-point
        await setup_smartapp_endpoint(self.hass)

        if not validate_webhook_requirements(self.hass):
            errors["base"] = "base_url_not_https"
            return self._show_step_user(errors)

        try:
            app = await find_app(self.hass, self.api)
            if app:
                await app.refresh()  # load all attributes
                await update_app(self.hass, app)
                # Get oauth client id/secret by regenerating it
                app_oauth = AppOAuth(app.app_id)
                app_oauth.client_name = APP_OAUTH_CLIENT_NAME
                app_oauth.scope.extend(APP_OAUTH_SCOPES)
                client = await self.api.generate_app_oauth(app_oauth)
            else:
                app, client = await create_app(self.hass, self.api)
            setup_smartapp(self.hass, app)
            self.app_id = app.app_id
            self.oauth_client_secret = client.client_secret
            self.oauth_client_id = client.client_id

        except APIResponseError as ex:
            if ex.is_target_error():
                errors["base"] = "webhook_error"
            else:
                errors["base"] = "app_setup_error"
            _LOGGER.exception(
                "API error setting up the SmartApp: %s", ex.raw_error_response
            )
            return self._show_step_user(errors)
        except ClientResponseError as ex:
            if ex.status == 401:
                errors[CONF_ACCESS_TOKEN] = "token_unauthorized"
            elif ex.status == 403:
                errors[CONF_ACCESS_TOKEN] = "token_forbidden"
            else:
                errors["base"] = "app_setup_error"
                _LOGGER.exception("Unexpected error setting up the SmartApp")
            return self._show_step_user(errors)
        except Exception:  # pylint:disable=broad-except
            errors["base"] = "app_setup_error"
            _LOGGER.exception("Unexpected error setting up the SmartApp")
            return self._show_step_user(errors)

        return await self.async_step_wait_install()
Пример #39
0
async def mock_responses(
    hass: HomeAssistant,
    aioclient_mock: AiohttpClientMocker,
    token: str = TOKEN,
    error: bool = False,
):
    """Mock responses from Efergy."""
    base_url = "https://engage.efergy.com/mobile_proxy/"
    api = Efergy(token,
                 session=async_get_clientsession(hass),
                 utc_offset="America/New_York")
    assert api._utc_offset == 300
    if error:
        aioclient_mock.get(
            f"{base_url}getInstant?token={token}",
            exc=exceptions.ConnectError,
        )
        return
    aioclient_mock.get(
        f"{base_url}getStatus?token={token}",
        text=load_fixture("efergy/status.json"),
    )
    aioclient_mock.get(
        f"{base_url}getInstant?token={token}",
        text=load_fixture("efergy/instant.json"),
    )
    aioclient_mock.get(
        f"{base_url}getEnergy?period=day",
        text=load_fixture("efergy/daily_energy.json"),
    )
    aioclient_mock.get(
        f"{base_url}getEnergy?period=week",
        text=load_fixture("efergy/weekly_energy.json"),
    )
    aioclient_mock.get(
        f"{base_url}getEnergy?period=month",
        text=load_fixture("efergy/monthly_energy.json"),
    )
    aioclient_mock.get(
        f"{base_url}getEnergy?period=year",
        text=load_fixture("efergy/yearly_energy.json"),
    )
    aioclient_mock.get(
        f"{base_url}getBudget?token={token}",
        text=load_fixture("efergy/budget.json"),
    )
    aioclient_mock.get(
        f"{base_url}getCost?period=day",
        text=load_fixture("efergy/daily_cost.json"),
    )
    aioclient_mock.get(
        f"{base_url}getCost?period=week",
        text=load_fixture("efergy/weekly_cost.json"),
    )
    aioclient_mock.get(
        f"{base_url}getCost?period=month",
        text=load_fixture("efergy/monthly_cost.json"),
    )
    aioclient_mock.get(
        f"{base_url}getCost?period=year",
        text=load_fixture("efergy/yearly_cost.json"),
    )
    if token == TOKEN:
        aioclient_mock.get(
            f"{base_url}getCurrentValuesSummary?token={token}",
            text=load_fixture("efergy/current_values_single.json"),
        )
    else:
        aioclient_mock.get(
            f"{base_url}getCurrentValuesSummary?token={token}",
            text=load_fixture("efergy/current_values_multi.json"),
        )
Пример #40
0
async def async_get_service(hass, config, discovery_info=None):
    """Get the mobile_app notification service."""
    session = async_get_clientsession(hass)
    return MobileAppNotificationService(session)
Пример #41
0
async def async_setup_entry(hass: HomeAssistantType,
                            entry: ConfigEntry) -> bool:
    """Set up AdGuard Home from a config entry."""
    session = async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL])
    adguard = AdGuardHome(
        entry.data[CONF_HOST],
        port=entry.data[CONF_PORT],
        username=entry.data[CONF_USERNAME],
        password=entry.data[CONF_PASSWORD],
        tls=entry.data[CONF_SSL],
        verify_ssl=entry.data[CONF_VERIFY_SSL],
        session=session,
    )

    hass.data.setdefault(DOMAIN, {})[DATA_ADGUARD_CLIENT] = adguard

    try:
        version = await adguard.version()
    except AdGuardHomeConnectionError as exception:
        raise ConfigEntryNotReady from exception

    if LooseVersion(MIN_ADGUARD_HOME_VERSION) > LooseVersion(version):
        _LOGGER.error(
            "This integration requires AdGuard Home v0.99.0 or higher to work correctly"
        )
        raise ConfigEntryNotReady

    for component in "sensor", "switch":
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    async def add_url(call) -> None:
        """Service call to add a new filter subscription to AdGuard Home."""
        await adguard.filtering.add_url(call.data.get(CONF_NAME),
                                        call.data.get(CONF_URL))

    async def remove_url(call) -> None:
        """Service call to remove a filter subscription from AdGuard Home."""
        await adguard.filtering.remove_url(call.data.get(CONF_URL))

    async def enable_url(call) -> None:
        """Service call to enable a filter subscription in AdGuard Home."""
        await adguard.filtering.enable_url(call.data.get(CONF_URL))

    async def disable_url(call) -> None:
        """Service call to disable a filter subscription in AdGuard Home."""
        await adguard.filtering.disable_url(call.data.get(CONF_URL))

    async def refresh(call) -> None:
        """Service call to refresh the filter subscriptions in AdGuard Home."""
        await adguard.filtering.refresh(call.data.get(CONF_FORCE))

    hass.services.async_register(DOMAIN,
                                 SERVICE_ADD_URL,
                                 add_url,
                                 schema=SERVICE_ADD_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_REMOVE_URL,
                                 remove_url,
                                 schema=SERVICE_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_ENABLE_URL,
                                 enable_url,
                                 schema=SERVICE_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_DISABLE_URL,
                                 disable_url,
                                 schema=SERVICE_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_REFRESH,
                                 refresh,
                                 schema=SERVICE_REFRESH_SCHEMA)

    return True
Пример #42
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up AdGuard Home from a config entry."""
    session = async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL])
    adguard = AdGuardHome(
        entry.data[CONF_HOST],
        port=entry.data[CONF_PORT],
        username=entry.data[CONF_USERNAME],
        password=entry.data[CONF_PASSWORD],
        tls=entry.data[CONF_SSL],
        verify_ssl=entry.data[CONF_VERIFY_SSL],
        session=session,
    )

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

    try:
        await adguard.version()
    except AdGuardHomeConnectionError as exception:
        raise ConfigEntryNotReady from exception

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    async def add_url(call: ServiceCall) -> None:
        """Service call to add a new filter subscription to AdGuard Home."""
        await adguard.filtering.add_url(allowlist=False,
                                        name=call.data[CONF_NAME],
                                        url=call.data[CONF_URL])

    async def remove_url(call: ServiceCall) -> None:
        """Service call to remove a filter subscription from AdGuard Home."""
        await adguard.filtering.remove_url(allowlist=False,
                                           url=call.data[CONF_URL])

    async def enable_url(call: ServiceCall) -> None:
        """Service call to enable a filter subscription in AdGuard Home."""
        await adguard.filtering.enable_url(allowlist=False,
                                           url=call.data[CONF_URL])

    async def disable_url(call: ServiceCall) -> None:
        """Service call to disable a filter subscription in AdGuard Home."""
        await adguard.filtering.disable_url(allowlist=False,
                                            url=call.data[CONF_URL])

    async def refresh(call: ServiceCall) -> None:
        """Service call to refresh the filter subscriptions in AdGuard Home."""
        await adguard.filtering.refresh(allowlist=False,
                                        force=call.data[CONF_FORCE])

    hass.services.async_register(DOMAIN,
                                 SERVICE_ADD_URL,
                                 add_url,
                                 schema=SERVICE_ADD_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_REMOVE_URL,
                                 remove_url,
                                 schema=SERVICE_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_ENABLE_URL,
                                 enable_url,
                                 schema=SERVICE_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_DISABLE_URL,
                                 disable_url,
                                 schema=SERVICE_URL_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_REFRESH,
                                 refresh,
                                 schema=SERVICE_REFRESH_SCHEMA)

    return True
Пример #43
0
        if tokens.get(ACCESS_TOKEN_EXPIRES) is not None and (
                expires := dt_util.parse_datetime(
                    tokens[ACCESS_TOKEN_EXPIRES])):
            tokens[ACCESS_TOKEN_EXPIRES] = _dt_aware_to_naive(expires)

        user_data = tokens.pop(USER_DATA, None)
        return (tokens, user_data)

    store = Store[dict[str, Any]](hass, STORAGE_VER, STORAGE_KEY)
    tokens, user_data = await load_auth_tokens(store)

    client_v2 = evohomeasync2.EvohomeClient(
        config[DOMAIN][CONF_USERNAME],
        config[DOMAIN][CONF_PASSWORD],
        **tokens,
        session=async_get_clientsession(hass),
    )

    try:
        await client_v2.login()
    except (aiohttp.ClientError, evohomeasync2.AuthenticationError) as err:
        _handle_exception(err)
        return False
    finally:
        config[DOMAIN][CONF_PASSWORD] = "REDACTED"

    loc_idx = config[DOMAIN][CONF_LOCATION_IDX]
    try:
        loc_config = client_v2.installation_info[loc_idx]
    except IndexError:
        _LOGGER.error(
Пример #44
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Tomorrow.io API from a config entry."""
    hass.data.setdefault(DOMAIN, {})

    # Let's precreate the device so that if this is a first time setup for a config
    # entry imported from a ClimaCell entry, we can apply customizations from the old
    # device.
    dev_reg = dr.async_get(hass)
    device = dev_reg.async_get_or_create(
        config_entry_id=entry.entry_id,
        identifiers={(DOMAIN, entry.data[CONF_API_KEY])},
        name=INTEGRATION_NAME,
        manufacturer=INTEGRATION_NAME,
        sw_version="v4",
        entry_type=dr.DeviceEntryType.SERVICE,
    )

    # If this is an import and we still have the old config entry ID in the entry data,
    # it means we are setting this entry up for the first time after a migration from
    # ClimaCell to Tomorrow.io. In order to preserve any customizations on the ClimaCell
    # entities, we need to remove each old entity, creating a new entity in its place
    # but attached to this entry.
    if entry.source == SOURCE_IMPORT and "old_config_entry_id" in entry.data:
        # Remove the old config entry ID from the entry data so we don't try this again
        # on the next setup
        data = entry.data.copy()
        old_config_entry_id = data.pop("old_config_entry_id")
        hass.config_entries.async_update_entry(entry, data=data)
        _LOGGER.debug(
            ("Setting up imported climacell entry %s for the first time as "
             "tomorrowio entry %s"),
            old_config_entry_id,
            entry.entry_id,
        )

        ent_reg = er.async_get(hass)
        for entity_entry in er.async_entries_for_config_entry(
                ent_reg, old_config_entry_id):
            _LOGGER.debug("Removing %s", entity_entry.entity_id)
            ent_reg.async_remove(entity_entry.entity_id)
            # In case the API key has changed due to a V3 -> V4 change, we need to
            # generate the new entity's unique ID
            new_unique_id = (
                f"{entry.data[CONF_API_KEY]}_"
                f"{'_'.join(entity_entry.unique_id.split('_')[1:])}")
            _LOGGER.debug("Re-creating %s for the new config entry",
                          entity_entry.entity_id)
            # We will precreate the entity so that any customizations can be preserved
            new_entity_entry = ent_reg.async_get_or_create(
                entity_entry.domain,
                DOMAIN,
                new_unique_id,
                suggested_object_id=entity_entry.entity_id.split(".")[1],
                disabled_by=entity_entry.disabled_by,
                config_entry=entry,
                original_name=entity_entry.original_name,
                original_icon=entity_entry.original_icon,
            )
            _LOGGER.debug("Re-created %s", new_entity_entry.entity_id)
            # If there are customizations on the old entity, apply them to the new one
            if entity_entry.name or entity_entry.icon:
                ent_reg.async_update_entity(
                    new_entity_entry.entity_id,
                    name=entity_entry.name,
                    icon=entity_entry.icon,
                )

        # We only have one device in the registry but we will do a loop just in case
        for old_device in dr.async_entries_for_config_entry(
                dev_reg, old_config_entry_id):
            if old_device.name_by_user:
                dev_reg.async_update_device(
                    device.id, name_by_user=old_device.name_by_user)

        # Remove the old config entry and now the entry is fully migrated
        hass.async_create_task(
            hass.config_entries.async_remove(old_config_entry_id))

    api = TomorrowioV4(
        entry.data[CONF_API_KEY],
        entry.data[CONF_LATITUDE],
        entry.data[CONF_LONGITUDE],
        session=async_get_clientsession(hass),
    )

    coordinator = TomorrowioDataUpdateCoordinator(
        hass,
        entry,
        api,
        _set_update_interval(hass, entry),
    )

    await coordinator.async_config_entry_first_refresh()

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

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Пример #45
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Weatherbit forecast as config entry."""

    if not entry.options:
        hass.config_entries.async_update_entry(
            entry,
            options={
                "fcs_update_interval": entry.data[CONF_FCS_UPDATE_INTERVAL],
                "cur_update_interval": entry.data[CONF_CUR_UPDATE_INTERVAL],
                "fcst_language": entry.data[CONF_FORECAST_LANGUAGE],
                "wind_unit": entry.data.get(CONF_WIND_UNITS, UNIT_WIND_MS),
            },
        )

    session = aiohttp_client.async_get_clientsession(hass)

    weatherbit = Weatherbit(
        entry.data[CONF_API_KEY],
        entry.data[CONF_LATITUDE],
        entry.data[CONF_LONGITUDE],
        entry.options.get(CONF_FORECAST_LANGUAGE, DEFAULT_FORECAST_LANGUAGE),
        "M",
        session,
    )
    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = weatherbit
    _LOGGER.debug("Connected to Weatherbit")

    if entry.options.get(CONF_FCS_UPDATE_INTERVAL):
        fcst_scan_interval = timedelta(
            minutes=entry.options[CONF_FCS_UPDATE_INTERVAL])
    else:
        fcst_scan_interval = SCAN_INTERVAL

    fcst_coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name=DOMAIN,
        update_method=weatherbit.async_get_forecast_daily,
        update_interval=fcst_scan_interval,
    )

    if entry.data.get(CONF_ADD_ALERTS):
        alert_coordinator = DataUpdateCoordinator(
            hass,
            _LOGGER,
            name=DOMAIN,
            update_method=weatherbit.async_get_weather_alerts,
            update_interval=fcst_scan_interval,
        )
    else:
        alert_coordinator = None

    if entry.options.get(CONF_CUR_UPDATE_INTERVAL):
        current_scan_interval = timedelta(
            minutes=entry.options[CONF_CUR_UPDATE_INTERVAL])
    else:
        current_scan_interval = SCAN_INTERVAL

    cur_coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name=DOMAIN,
        update_method=weatherbit.async_get_current_data,
        update_interval=current_scan_interval,
    )

    try:
        await weatherbit.async_get_city_name()
    except InvalidApiKey:
        _LOGGER.error(
            "Your API Key is invalid or does not support this operation")
        return False
    except (RequestError, ServerDisconnectedError) as err:
        _LOGGER.warning(str(err))
        raise ConfigEntryNotReady

    await fcst_coordinator.async_refresh()
    await cur_coordinator.async_refresh()
    if entry.data.get(CONF_ADD_ALERTS):
        await alert_coordinator.async_refresh()

    hass.data[DOMAIN][entry.entry_id] = {
        "fcst_coordinator": fcst_coordinator,
        "cur_coordinator": cur_coordinator,
        "alert_coordinator": alert_coordinator,
        "weatherbit": weatherbit,
        "wind_unit_metric": entry.options.get(CONF_WIND_UNITS, UNIT_WIND_MS),
    }

    await _async_get_or_create_weatherbit_device_in_registry(hass, entry)

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

    if not entry.update_listeners:
        entry.add_update_listener(async_update_options)

    return True
Пример #46
0
 async def validate_input(self, api_key: str, ferry_from: str,
                          ferry_to: str) -> None:
     """Validate input from user input."""
     web_session = async_get_clientsession(self.hass)
     ferry_api = TrafikverketFerry(web_session, api_key)
     await ferry_api.async_get_next_ferry_stop(ferry_from, ferry_to)
Пример #47
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
    """Set up Control4 from a config entry."""
    entry_data = hass.data[DOMAIN].setdefault(entry.entry_id, {})
    account_session = aiohttp_client.async_get_clientsession(hass)

    config = entry.data
    account = C4Account(config[CONF_USERNAME], config[CONF_PASSWORD], account_session)
    try:
        await account.getAccountBearerToken()
    except client_exceptions.ClientError as exception:
        _LOGGER.error("Error connecting to Control4 account API: %s", exception)
        raise ConfigEntryNotReady from exception
    except BadCredentials as exception:
        _LOGGER.error(
            "Error authenticating with Control4 account API, incorrect username or password: %s",
            exception,
        )
        return False
    entry_data[CONF_ACCOUNT] = account

    controller_unique_id = config[CONF_CONTROLLER_UNIQUE_ID]
    entry_data[CONF_CONTROLLER_UNIQUE_ID] = controller_unique_id

    director_token_dict = await account.getDirectorBearerToken(controller_unique_id)
    director_session = aiohttp_client.async_get_clientsession(hass, verify_ssl=False)

    director = C4Director(
        config[CONF_HOST], director_token_dict[CONF_TOKEN], director_session
    )
    entry_data[CONF_DIRECTOR] = director
    entry_data[CONF_DIRECTOR_TOKEN_EXPIRATION] = director_token_dict["token_expiration"]

    # Add Control4 controller to device registry
    controller_href = (await account.getAccountControllers())["href"]
    entry_data[CONF_DIRECTOR_SW_VERSION] = await account.getControllerOSVersion(
        controller_href
    )

    _, model, mac_address = controller_unique_id.split("_", 3)
    entry_data[CONF_DIRECTOR_MODEL] = model.upper()

    device_registry = await dr.async_get_registry(hass)
    device_registry.async_get_or_create(
        config_entry_id=entry.entry_id,
        identifiers={(DOMAIN, controller_unique_id)},
        connections={(dr.CONNECTION_NETWORK_MAC, mac_address)},
        manufacturer="Control4",
        name=controller_unique_id,
        model=entry_data[CONF_DIRECTOR_MODEL],
        sw_version=entry_data[CONF_DIRECTOR_SW_VERSION],
    )

    # Store all items found on controller for platforms to use
    director_all_items = await director.getAllItemInfo()
    director_all_items = json.loads(director_all_items)
    entry_data[CONF_DIRECTOR_ALL_ITEMS] = director_all_items

    # Load options from config entry
    entry_data[CONF_SCAN_INTERVAL] = entry.options.get(
        CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
    )

    entry_data[CONF_CONFIG_LISTENER] = entry.add_update_listener(update_listener)

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

    return True
Пример #48
0
async def async_setup_entry(hass, entry):
    """Set up Plex from a config entry."""
    server_config = entry.data[PLEX_SERVER_CONFIG]

    if MP_DOMAIN not in entry.options:
        options = dict(entry.options)
        options.setdefault(
            MP_DOMAIN,
            hass.data.get(PLEX_MEDIA_PLAYER_OPTIONS)
            or MEDIA_PLAYER_SCHEMA({}),
        )
        hass.config_entries.async_update_entry(entry, options=options)

    plex_server = PlexServer(hass, server_config, entry.options)
    try:
        await hass.async_add_executor_job(plex_server.connect)
    except requests.exceptions.ConnectionError as error:
        _LOGGER.error(
            "Plex server (%s) could not be reached: [%s]",
            server_config[CONF_URL],
            error,
        )
        return False
    except (
            plexapi.exceptions.BadRequest,
            plexapi.exceptions.Unauthorized,
            plexapi.exceptions.NotFound,
    ) as error:
        _LOGGER.error(
            "Login to %s failed, verify token and SSL settings: [%s]",
            entry.data[CONF_SERVER],
            error,
        )
        return False

    _LOGGER.debug("Connected to: %s (%s)", plex_server.friendly_name,
                  plex_server.url_in_use)
    server_id = plex_server.machine_identifier
    hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server

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

    entry.add_update_listener(async_options_updated)

    unsub = async_dispatcher_connect(
        hass,
        PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
        plex_server.update_platforms,
    )
    hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    def update_plex():
        async_dispatcher_send(hass,
                              PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id))

    session = async_get_clientsession(hass)
    verify_ssl = server_config.get(CONF_VERIFY_SSL)
    websocket = PlexWebsocket(plex_server.plex_server,
                              update_plex,
                              session=session,
                              verify_ssl=verify_ssl)
    hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket

    async def async_start_websocket_session(_):
        await websocket.listen()

    def close_websocket_session(_):
        websocket.close()

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START,
                               async_start_websocket_session)

    unsub = hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       close_websocket_session)
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    return True
Пример #49
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up sma from a config entry."""
    # Init the SMA interface
    protocol = "https" if entry.data[CONF_SSL] else "http"
    url = f"{protocol}://{entry.data[CONF_HOST]}"
    verify_ssl = entry.data[CONF_VERIFY_SSL]
    group = entry.data[CONF_GROUP]
    password = entry.data[CONF_PASSWORD]

    session = async_get_clientsession(hass, verify_ssl=verify_ssl)
    sma = pysma.SMA(session, url, password, group)

    try:
        # Get updated device info
        sma_device_info = await sma.device_info()
        # Get all device sensors
        sensor_def = await sma.get_sensors()
    except (
            pysma.exceptions.SmaReadException,
            pysma.exceptions.SmaConnectionException,
    ) as exc:
        raise ConfigEntryNotReady from exc

    if TYPE_CHECKING:
        assert entry.unique_id

    # Create DeviceInfo object from sma_device_info
    device_info = DeviceInfo(
        configuration_url=url,
        identifiers={(DOMAIN, entry.unique_id)},
        manufacturer=sma_device_info["manufacturer"],
        model=sma_device_info["type"],
        name=sma_device_info["name"],
        sw_version=sma_device_info["sw_version"],
    )

    # Define the coordinator
    async def async_update_data():
        """Update the used SMA sensors."""
        try:
            await sma.read(sensor_def)
        except (
                pysma.exceptions.SmaReadException,
                pysma.exceptions.SmaConnectionException,
        ) as exc:
            raise UpdateFailed(exc) from exc

    interval = timedelta(
        seconds=entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL))

    coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name="sma",
        update_method=async_update_data,
        update_interval=interval,
    )

    try:
        await coordinator.async_config_entry_first_refresh()
    except ConfigEntryNotReady:
        await sma.close_session()
        raise

    # Ensure we logout on shutdown
    async def async_close_session(event):
        """Close the session."""
        await sma.close_session()

    remove_stop_listener = hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                                      async_close_session)

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.entry_id] = {
        PYSMA_OBJECT: sma,
        PYSMA_COORDINATOR: coordinator,
        PYSMA_SENSORS: sensor_def,
        PYSMA_REMOVE_LISTENER: remove_stop_listener,
        PYSMA_DEVICE_INFO: device_info,
    }

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Пример #50
0
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Setup a Synology IP Camera."""
    verify_ssl = config.get(CONF_VERIFY_SSL)
    websession_init = async_get_clientsession(hass, verify_ssl)

    # Determine API to use for authentication
    syno_api_url = SYNO_API_URL.format(config.get(CONF_URL), WEBAPI_PATH,
                                       QUERY_CGI)

    query_payload = {
        'api': QUERY_API,
        'method': 'Query',
        'version': '1',
        'query': 'SYNO.'
    }
    query_req = None
    try:
        with async_timeout.timeout(TIMEOUT, loop=hass.loop):
            query_req = yield from websession_init.get(syno_api_url,
                                                       params=query_payload)

        query_resp = yield from query_req.json()
        auth_path = query_resp['data'][AUTH_API]['path']
        camera_api = query_resp['data'][CAMERA_API]['path']
        camera_path = query_resp['data'][CAMERA_API]['path']
        streaming_path = query_resp['data'][STREAMING_API]['path']

    except (asyncio.TimeoutError, aiohttp.errors.ClientError):
        _LOGGER.exception("Error on %s", syno_api_url)
        return False

    finally:
        if query_req is not None:
            yield from query_req.release()

    # Authticate to NAS to get a session id
    syno_auth_url = SYNO_API_URL.format(config.get(CONF_URL), WEBAPI_PATH,
                                        auth_path)

    session_id = yield from get_session_id(hass, websession_init,
                                           config.get(CONF_USERNAME),
                                           config.get(CONF_PASSWORD),
                                           syno_auth_url)

    # init websession
    websession = async_create_clientsession(hass,
                                            verify_ssl,
                                            cookies={'id': session_id})

    # Use SessionID to get cameras in system
    syno_camera_url = SYNO_API_URL.format(config.get(CONF_URL), WEBAPI_PATH,
                                          camera_api)

    camera_payload = {'api': CAMERA_API, 'method': 'List', 'version': '1'}
    try:
        with async_timeout.timeout(TIMEOUT, loop=hass.loop):
            camera_req = yield from websession.get(syno_camera_url,
                                                   params=camera_payload)
    except (asyncio.TimeoutError, aiohttp.errors.ClientError):
        _LOGGER.exception("Error on %s", syno_camera_url)
        return False

    camera_resp = yield from camera_req.json()
    cameras = camera_resp['data']['cameras']
    yield from camera_req.release()

    # add cameras
    devices = []
    for camera in cameras:
        if not config.get(CONF_WHITELIST):
            camera_id = camera['id']
            snapshot_path = camera['snapshot_path']

            device = SynologyCamera(hass, websession, config, camera_id,
                                    camera['name'], snapshot_path,
                                    streaming_path, camera_path, auth_path)
            devices.append(device)

    yield from async_add_devices(devices)
Пример #51
0
    async def _async_send_message(self, message, targets, data):
        conversations = []
        for target in targets:
            conversation = None
            if CONF_CONVERSATION_ID in target:
                conversation = self._conversation_list.get(target[CONF_CONVERSATION_ID])
            elif CONF_CONVERSATION_NAME in target:
                conversation = self._resolve_conversation_name(
                    target[CONF_CONVERSATION_NAME]
                )
            if conversation is not None:
                conversations.append(conversation)

        if not conversations:
            return False

        from hangups import ChatMessageSegment, hangouts_pb2

        messages = []
        for segment in message:
            if messages:
                messages.append(
                    ChatMessageSegment(
                        "", segment_type=hangouts_pb2.SEGMENT_TYPE_LINE_BREAK
                    )
                )
            if "parse_str" in segment and segment["parse_str"]:
                messages.extend(ChatMessageSegment.from_str(segment["text"]))
            else:
                if "parse_str" in segment:
                    del segment["parse_str"]
                messages.append(ChatMessageSegment(**segment))

        image_file = None
        if data:
            if data.get("image_url"):
                uri = data.get("image_url")
                try:
                    websession = async_get_clientsession(self.hass)
                    async with websession.get(uri, timeout=5) as response:
                        if response.status != 200:
                            _LOGGER.error(
                                "Fetch image failed, %s, %s", response.status, response
                            )
                            image_file = None
                        else:
                            image_data = await response.read()
                            image_file = io.BytesIO(image_data)
                            image_file.name = "image.png"
                except (asyncio.TimeoutError, aiohttp.ClientError) as error:
                    _LOGGER.error("Failed to fetch image, %s", type(error))
                    image_file = None
            elif data.get("image_file"):
                uri = data.get("image_file")
                if self.hass.config.is_allowed_path(uri):
                    try:
                        image_file = open(uri, "rb")
                    except IOError as error:
                        _LOGGER.error(
                            "Image file I/O error(%s): %s", error.errno, error.strerror
                        )
                else:
                    _LOGGER.error('Path "%s" not allowed', uri)

        if not messages:
            return False
        for conv in conversations:
            await conv.send_message(messages, image_file)
Пример #52
0
    async def async_step_user(self, user_input: dict[str, Any] = None) -> FlowResult:
        """Handle the initial step."""
        errors = {}
        if user_input is not None:
            # Grab the API key and add it to the rest of the config before continuing
            if self._import_config:
                self._import_config[CONF_API_KEY] = user_input[CONF_API_KEY]
                self._import_config[CONF_LOCATION] = {
                    CONF_LATITUDE: self._import_config.pop(
                        CONF_LATITUDE, self.hass.config.latitude
                    ),
                    CONF_LONGITUDE: self._import_config.pop(
                        CONF_LONGITUDE, self.hass.config.longitude
                    ),
                }
                user_input = self._import_config.copy()
            await self.async_set_unique_id(
                unique_id=_get_unique_id(self.hass, user_input)
            )
            self._abort_if_unique_id_configured()

            location = user_input[CONF_LOCATION]
            latitude = location[CONF_LATITUDE]
            longitude = location[CONF_LONGITUDE]
            if CONF_NAME not in user_input:
                user_input[CONF_NAME] = DEFAULT_NAME
                # Append zone name if it exists and we are using the default name
                if zone_state := async_active_zone(self.hass, latitude, longitude):
                    zone_name = zone_state.attributes[CONF_FRIENDLY_NAME]
                    user_input[CONF_NAME] += f" - {zone_name}"
            try:
                await TomorrowioV4(
                    user_input[CONF_API_KEY],
                    str(latitude),
                    str(longitude),
                    session=async_get_clientsession(self.hass),
                ).realtime([TMRW_ATTR_TEMPERATURE])
            except CantConnectException:
                errors["base"] = "cannot_connect"
            except InvalidAPIKeyException:
                errors[CONF_API_KEY] = "invalid_api_key"
            except RateLimitedException:
                errors[CONF_API_KEY] = "rate_limited"
            except Exception:  # pylint: disable=broad-except
                _LOGGER.exception("Unexpected exception")
                errors["base"] = "unknown"

            if not errors:
                options: Mapping[str, Any] = {CONF_TIMESTEP: DEFAULT_TIMESTEP}
                # Store the old config entry ID and retrieve options to recreate the entry
                if self.source == config_entries.SOURCE_IMPORT:
                    old_config_entry_id = self.context["old_config_entry_id"]
                    old_config_entry = self.hass.config_entries.async_get_entry(
                        old_config_entry_id
                    )
                    assert old_config_entry
                    options = dict(old_config_entry.options)
                    user_input["old_config_entry_id"] = old_config_entry_id
                return self.async_create_entry(
                    title=user_input[CONF_NAME],
                    data=user_input,
                    options=options,
                )
Пример #53
0
 def async_turn_off(self):
     """Turn the device off."""
     websession = async_get_clientsession(self.hass)
     with async_timeout.timeout(self._timeout, loop=self.hass.loop):
         req = yield from websession.post(self._res_off)
         text = yield from req.text()
Пример #54
0
    def __init__(self, hass, name, host, port, tcp_port, encryption=False,
                 username=None, password=None,
                 turn_on_action=None, turn_off_action=None,
                 timeout=DEFAULT_TIMEOUT, websocket=True,
                 unique_id=None):
        """Initialize the Kodi device."""
        import jsonrpc_async
        import jsonrpc_websocket
        self.hass = hass
        self._name = name
        self._unique_id = unique_id
        self._media_position_updated_at = None
        self._media_position = None

        kwargs = {
            'timeout': timeout,
            'session': async_get_clientsession(hass),
        }

        if username is not None:
            kwargs['auth'] = aiohttp.BasicAuth(username, password)
            image_auth_string = "{}:{}@".format(username, password)
        else:
            image_auth_string = ""

        http_protocol = 'https' if encryption else 'http'
        ws_protocol = 'wss' if encryption else 'ws'

        self._http_url = '{}://{}:{}/jsonrpc'.format(http_protocol, host, port)
        self._image_url = '{}://{}{}:{}/image'.format(
            http_protocol, image_auth_string, host, port)
        self._ws_url = '{}://{}:{}/jsonrpc'.format(ws_protocol, host, tcp_port)

        self._http_server = jsonrpc_async.Server(self._http_url, **kwargs)
        if websocket:
            # Setup websocket connection
            self._ws_server = jsonrpc_websocket.Server(self._ws_url, **kwargs)

            # Register notification listeners
            self._ws_server.Player.OnPause = self.async_on_speed_event
            self._ws_server.Player.OnPlay = self.async_on_speed_event
            self._ws_server.Player.OnAVStart = self.async_on_speed_event
            self._ws_server.Player.OnAVChange = self.async_on_speed_event
            self._ws_server.Player.OnResume = self.async_on_speed_event
            self._ws_server.Player.OnSpeedChanged = self.async_on_speed_event
            self._ws_server.Player.OnSeek = self.async_on_speed_event
            self._ws_server.Player.OnStop = self.async_on_stop
            self._ws_server.Application.OnVolumeChanged = \
                self.async_on_volume_changed
            self._ws_server.System.OnQuit = self.async_on_quit
            self._ws_server.System.OnRestart = self.async_on_quit
            self._ws_server.System.OnSleep = self.async_on_quit

            def on_hass_stop(event):
                """Close websocket connection when hass stops."""
                self.hass.async_create_task(self._ws_server.close())

            self.hass.bus.async_listen_once(
                EVENT_HOMEASSISTANT_STOP, on_hass_stop)
        else:
            self._ws_server = None

        # Script creation for the turn on/off config options
        if turn_on_action is not None:
            turn_on_action = script.Script(
                self.hass, turn_on_action,
                "{} turn ON script".format(self.name),
                self.async_update_ha_state(True))
        if turn_off_action is not None:
            turn_off_action = script.Script(
                self.hass, _check_deprecated_turn_off(hass, turn_off_action),
                "{} turn OFF script".format(self.name))
        self._turn_on_action = turn_on_action
        self._turn_off_action = turn_off_action
        self._enable_websocket = websocket
        self._players = list()
        self._properties = {}
        self._item = {}
        self._app_properties = {}
Пример #55
0
    async def update(self):
        """Update function for updating api information."""
        try:
            url = BSE_URL.format(self.area)

            hdr = {
                "User-Agent":
                ("mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/78.0.3904.70 safari/537.36"
                 )
            }

            session = async_get_clientsession(self.hass)

            # response = requests.get(url, headers=hdr, timeout=10)
            response = await session.get(url, headers=hdr, timeout=30)
            response.raise_for_status()

            soup = BeautifulSoup(await response.text(), "html.parser")

            NowTemp = ""
            CheckDust = []

            # 지역
            LocationInfo = soup.find("span", {"class": "btn_select"}).text

            # 현재 온도
            NowTemp = soup.find("span", {"class": "todaytemp"}).text

            # 날씨 캐스트
            WeatherCast = soup.find("p", {"class": "cast_txt"}).text

            # 오늘 오전온도, 오후온도, 체감온도
            TodayMinTemp = (soup.find("span", {
                "class": "min"
            }).select("span.num")[0].text)
            TodayMaxTemp = (soup.find("span", {
                "class": "max"
            }).select("span.num")[0].text)
            TodayFeelTemp = (soup.find("span", {
                "class": "sensible"
            }).select("em > span.num")[0].text)

            # 시간당 강수량
            TodayRainfall = soup.find("span", {"class": "rainfall"})
            Rainfall = "-"

            if TodayRainfall is not None:
                TodayRainfallSelect = TodayRainfall.select("em > span.num")

                for rain in TodayRainfallSelect:
                    Rainfall = rain.text

            # 자외선 지수
            TodayUVSelect = soup.find("span", {
                "class": "indicator"
            }).select("span > span.num")
            TodayUV = "-"

            for uv in TodayUVSelect:
                TodayUV = uv.text

            # 미세먼지, 초미세먼지, 오존 지수
            CheckDust1 = soup.find("div", {"class": "sub_info"})
            CheckDust2 = CheckDust1.find("div", {"class": "detail_box"})

            for i in CheckDust2.select("dd"):
                CheckDust.append(i.text)

            FineDust = CheckDust[0].split("㎍/㎥")[0]
            FineDustGrade = CheckDust[0].split("㎍/㎥")[1]
            UltraFineDust = CheckDust[1].split("㎍/㎥")[0]
            UltraFineDustGrade = CheckDust[1].split("㎍/㎥")[1]

            # 오존
            Ozon = CheckDust[2].split("ppm")[0]
            OzonGrade = CheckDust[2].split("ppm")[1]

            # condition
            today_area = soup.find("div",
                                   {"class": "today_area _mainTabContent"})

            condition_main = today_area.select(
                "div.main_info > span.ico_state")[0]["class"][1]
            condition = CONDITIONS[condition_main][0]

            # 현재 습도
            humi_tab = soup.find(
                "div", {"class": "info_list humidity _tabContent _center"})
            Humidity = humi_tab.select(
                "ul > li.on.now > dl > dd.weather_item._dotWrapper > span"
            )[0].text

            # 현재풍속
            wind_tab = soup.find(
                "div", {"class": "info_list wind _tabContent _center"})
            WindSpeed = wind_tab.select(
                "ul > li.on.now > dl > dd.weather_item._dotWrapper > span"
            )[0].text
            WindState = wind_tab.select(
                "ul > li.on.now > dl > dd.item_condition > span.wt_status"
            )[0].text

            # 내일 오전, 오후 온도 및 상태 체크
            tomorrowArea = soup.find("div", {"class": "tomorrow_area"})
            tomorrowCheck = tomorrowArea.find_all(
                "div", {"class": "main_info morning_box"})

            # 내일 오전온도
            tomorrowMTemp = tomorrowCheck[0].find("span", {
                "class": "todaytemp"
            }).text

            # 내일 오전상태
            tomorrowMState1 = tomorrowCheck[0].find("div",
                                                    {"class": "info_data"})
            tomorrowMState2 = tomorrowMState1.find("ul",
                                                   {"class": "info_list"})
            tomorrowMState = tomorrowMState2.find("p", {
                "class": "cast_txt"
            }).text

            # 내일 오후온도
            tomorrowATemp1 = tomorrowCheck[1].find(
                "p", {"class": "info_temperature"})
            tomorrowATemp = tomorrowATemp1.find("span", {
                "class": "todaytemp"
            }).text

            # 내일 오후상태
            tomorrowAState1 = tomorrowCheck[1].find("div",
                                                    {"class": "info_data"})
            tomorrowAState2 = tomorrowAState1.find("ul",
                                                   {"class": "info_list"})
            tomorrowAState = tomorrowAState2.find("p", {
                "class": "cast_txt"
            }).text

            # 주간날씨
            weekly = soup.find("div",
                               {"class": "table_info weekly _weeklyWeather"})

            date_info = weekly.find_all("li", {"class": "date_info today"})

            # 비시작시간
            rain_tab = soup.find(
                "div", {"class": "info_list weather_condition _tabContent"})
            rainyStart = "-"
            rainyStartTmr = "-"

            if rain_tab is not None:
                # 오늘
                rainyStart = "비안옴"
                for rain_li in rain_tab.select("ul > li"):
                    if (rain_li.select("dl > dd.item_time")[0].find(
                            "span", {"class": "tomorrow"}) is not None):
                        break

                    if rain_li.select(
                            "dl > dd.item_condition > span")[0].text == "비":
                        rainyStart = (
                            rain_li.select("dl > dd.item_time")[0].find(
                                "span", {
                                    "class": None
                                }).text)
                        break

                # 오늘 ~ 내일
                rainyStartTmr = "비안옴"
                for rain_li in rain_tab.select("ul > li"):
                    if rain_li.select(
                            "dl > dd.item_condition > span")[0].text == "비":
                        rainyStartTmr = (
                            rain_li.select("dl > dd.item_time")[0].find(
                                "span", {
                                    "class": None
                                }).text)
                        break

            forecast = []

            reftime = datetime.now()

            for di in date_info:
                data = {}

                # day
                day = di.select("span.day_info")

                dayInfo = ""

                for t in day:
                    dayInfo = t.text.strip()
                    # data['datetime'] = dayInfo

                data["datetime"] = reftime

                # temp
                temp = di.select("dl > dd > span")
                temptext = ""

                for t in temp:
                    temptext += t.text

                arrTemp = temptext.split("/")

                data["templow"] = float(arrTemp[0])
                data["temperature"] = float(arrTemp[1])

                # condition
                condition_am = di.select(
                    "span.point_time.morning > span.ico_state2")[0]
                condition_pm = di.select(
                    "span.point_time.afternoon > span.ico_state2")[0]

                data["condition"] = CONDITIONS[condition_pm["class"][1]][0]
                data["condition_am"] = CONDITIONS[condition_am["class"][1]][2]
                data["condition_pm"] = CONDITIONS[condition_pm["class"][1]][2]

                # rain_rate
                rain_m = di.select(
                    "span.point_time.morning > span.rain_rate > span.num")
                for t in rain_m:
                    data["rain_rate_am"] = int(t.text)

                rain_a = di.select(
                    "span.point_time.afternoon > span.rain_rate > span.num")
                for t in rain_a:
                    data["rain_rate_pm"] = int(t.text)

                if dayInfo.split(" ")[1] != "오늘":
                    forecast.append(data)

                reftime = reftime + timedelta(days=1)

            self.forecast = forecast

            self.result = {
                LOCATION[0]: LocationInfo,
                NOW_CAST[0]: WeatherCast,
                NOW_TEMP[0]: NowTemp,
                NOW_HUMI[0]: Humidity,
                CONDITION[0]: condition,
                WIND_SPEED[0]: WindSpeed,
                WIND_DIR[0]: WindState,
                MIN_TEMP[0]: TodayMinTemp,
                MAX_TEMP[0]: TodayMaxTemp,
                FEEL_TEMP[0]: TodayFeelTemp,
                RAINFALL[0]: Rainfall,
                UV[0]: TodayUV,
                NDUST[0]: FineDust,
                NDUST_GRADE[0]: FineDustGrade,
                UDUST[0]: UltraFineDust,
                UDUST_GRADE[0]: UltraFineDustGrade,
                OZON[0]: Ozon,
                OZON_GRADE[0]: OzonGrade,
                TOMORROW_AM[0]: tomorrowMState,
                TOMORROW_MIN[0]: tomorrowMTemp,
                TOMORROW_PM[0]: tomorrowAState,
                TOMORROW_MAX[0]: tomorrowATemp,
                RAINY_START[0]: rainyStart,
                RAINY_START_TMR[0]: rainyStartTmr,
            }
            _LOGGER.info(
                f"[{BRAND}] Update weather information -> {self.result}")
            for id in WEATHER_INFO.keys():
                try:
                    self.device_update(id)
                except Exception as ex:
                    _LOGGER.info(f"[{BRAND}] Update weather fail -> {ex}")
        except Exception as ex:
            _LOGGER.error("Failed to update NWeather API status Error: %s", ex)
            raise
Пример #56
0
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up the IP Webcam component."""

    webcams = hass.data[DATA_IP_WEBCAM] = {}
    websession = async_get_clientsession(hass)

    async def async_setup_ipcamera(cam_config):
        """Set up an IP camera."""
        host = cam_config[CONF_HOST]
        username: str | None = cam_config.get(CONF_USERNAME)
        password: str | None = cam_config.get(CONF_PASSWORD)
        name: str = cam_config[CONF_NAME]
        interval = cam_config[CONF_SCAN_INTERVAL]
        switches = cam_config.get(CONF_SWITCHES)
        sensors = cam_config.get(CONF_SENSORS)
        motion = cam_config.get(CONF_MOTION_SENSOR)

        # Init ip webcam
        cam = PyDroidIPCam(
            websession,
            host,
            cam_config[CONF_PORT],
            username=username,
            password=password,
            timeout=cam_config[CONF_TIMEOUT],
            ssl=False,
        )

        if switches is None:
            switches = [
                setting for setting in cam.enabled_settings
                if setting in SWITCHES
            ]

        if sensors is None:
            sensors = [
                sensor for sensor in cam.enabled_sensors if sensor in SENSORS
            ]
            sensors.extend(["audio_connections", "video_connections"])

        if motion is None:
            motion = "motion_active" in cam.enabled_sensors

        async def async_update_data(now):
            """Update data from IP camera in SCAN_INTERVAL."""
            await cam.update()
            async_dispatcher_send(hass, SIGNAL_UPDATE_DATA, host)

            async_track_point_in_utc_time(hass, async_update_data,
                                          utcnow() + interval)

        await async_update_data(None)

        # Load platforms
        webcams[host] = cam

        mjpeg_camera = {
            CONF_MJPEG_URL: cam.mjpeg_url,
            CONF_STILL_IMAGE_URL: cam.image_url,
        }
        if username and password:
            mjpeg_camera.update({
                CONF_USERNAME: username,
                CONF_PASSWORD: password
            })

        # Remove incorrect config entry setup via mjpeg platform discovery.
        mjpeg_config_entry = next(
            (config_entry
             for config_entry in hass.config_entries.async_entries("mjpeg")
             if all(
                 config_entry.options.get(key) == val
                 for key, val in mjpeg_camera.items())),
            None,
        )
        if mjpeg_config_entry:
            await hass.config_entries.async_remove(mjpeg_config_entry.entry_id)

        mjpeg_camera[CONF_NAME] = name

        hass.async_create_task(
            discovery.async_load_platform(hass, Platform.CAMERA, DOMAIN,
                                          mjpeg_camera, config))

        if sensors:
            hass.async_create_task(
                discovery.async_load_platform(
                    hass,
                    Platform.SENSOR,
                    DOMAIN,
                    {
                        CONF_NAME: name,
                        CONF_HOST: host,
                        CONF_SENSORS: sensors
                    },
                    config,
                ))

        if switches:
            hass.async_create_task(
                discovery.async_load_platform(
                    hass,
                    Platform.SWITCH,
                    DOMAIN,
                    {
                        CONF_NAME: name,
                        CONF_HOST: host,
                        CONF_SWITCHES: switches
                    },
                    config,
                ))

        if motion:
            hass.async_create_task(
                discovery.async_load_platform(
                    hass,
                    Platform.BINARY_SENSOR,
                    DOMAIN,
                    {
                        CONF_HOST: host,
                        CONF_NAME: name
                    },
                    config,
                ))

    tasks = [async_setup_ipcamera(conf) for conf in config[DOMAIN]]
    if tasks:
        await asyncio.wait(tasks)

    return True
Пример #57
0
async def create_vehicle_proxy(
    hass: HomeAssistant, vehicle_type: str
) -> RenaultVehicleProxy:
    """Create a vehicle proxy for testing."""
    mock_vehicle = MOCK_VEHICLES[vehicle_type]
    mock_get_cockpit = schemas.KamereonVehicleDataResponseSchema.loads(
        load_fixture(mock_vehicle["endpoints"]["cockpit"])
        if "cockpit" in mock_vehicle["endpoints"]
        else "{}"
    ).get_attributes(schemas.KamereonVehicleCockpitDataSchema)
    mock_get_hvac_status = schemas.KamereonVehicleDataResponseSchema.loads(
        load_fixture(mock_vehicle["endpoints"]["hvac_status"])
        if "hvac_status" in mock_vehicle["endpoints"]
        else "{}"
    ).get_attributes(schemas.KamereonVehicleHvacStatusDataSchema)
    mock_get_battery_status = schemas.KamereonVehicleDataResponseSchema.loads(
        load_fixture(mock_vehicle["endpoints"]["battery_status"])
        if "battery_status" in mock_vehicle["endpoints"]
        else "{}"
    ).get_attributes(schemas.KamereonVehicleBatteryStatusDataSchema)
    mock_get_charge_mode = schemas.KamereonVehicleDataResponseSchema.loads(
        load_fixture(mock_vehicle["endpoints"]["charge_mode"])
        if "charge_mode" in mock_vehicle["endpoints"]
        else "{}"
    ).get_attributes(schemas.KamereonVehicleChargeModeDataSchema)
    mock_get_location = schemas.KamereonVehicleDataResponseSchema.loads(
        load_fixture(mock_vehicle["endpoints"]["location"])
        if "location" in mock_vehicle["endpoints"]
        else "{}"
    ).get_attributes(schemas.KamereonVehicleLocationDataSchema)

    vehicles_response: models.KamereonVehiclesResponse = (
        schemas.KamereonVehiclesResponseSchema.loads(
            load_fixture(f"vehicle_{vehicle_type}.json")
        )
    )
    vehicle_details = vehicles_response.vehicleLinks[0].vehicleDetails
    vehicle = RenaultVehicle(
        vehicles_response.accountId,
        vehicle_details.vin,
        websession=aiohttp_client.async_get_clientsession(hass),
    )

    vehicle_proxy = RenaultVehicleProxy(
        hass, vehicle, vehicle_details, timedelta(seconds=300), False
    )
    with patch(
        "custom_components.renault.renault_vehicle.RenaultVehicleProxy.endpoint_available",
        side_effect=mock_vehicle["endpoints_available"],
    ), patch(
        "custom_components.renault.renault_vehicle.RenaultVehicleProxy.get_cockpit",
        return_value=mock_get_cockpit,
    ), patch(
        "custom_components.renault.renault_vehicle.RenaultVehicleProxy.get_hvac_status",
        return_value=mock_get_hvac_status,
    ), patch(
        "custom_components.renault.renault_vehicle.RenaultVehicleProxy.get_battery_status",
        return_value=mock_get_battery_status,
    ), patch(
        "custom_components.renault.renault_vehicle.RenaultVehicleProxy.get_charge_mode",
        return_value=mock_get_charge_mode,
    ), patch(
        "custom_components.renault.renault_vehicle.RenaultVehicleProxy.get_location",
        return_value=mock_get_location,
    ):
        await vehicle_proxy.async_initialise()
    return vehicle_proxy
Пример #58
0
async def async_setup_entry(hass, config_entry):
    """Set up SimpliSafe as config entry."""
    _verify_domain_control = verify_domain_control(hass, DOMAIN)

    websession = aiohttp_client.async_get_clientsession(hass)

    try:
        api = await API.login_via_token(config_entry.data[CONF_TOKEN],
                                        websession)
    except InvalidCredentialsError:
        _LOGGER.error("Invalid credentials provided")
        return False
    except SimplipyError as err:
        _LOGGER.error("Config entry failed: %s", err)
        raise ConfigEntryNotReady

    _async_save_refresh_token(hass, config_entry, api.refresh_token)

    simplisafe = SimpliSafe(hass, api, config_entry)
    await simplisafe.async_init()
    hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = simplisafe

    for component in ("alarm_control_panel", "lock"):
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(
                config_entry, component))

    @callback
    def verify_system_exists(coro):
        """Log an error if a service call uses an invalid system ID."""
        async def decorator(call):
            """Decorate."""
            system_id = int(call.data[ATTR_SYSTEM_ID])
            if system_id not in simplisafe.systems:
                _LOGGER.error("Unknown system ID in service call: %s",
                              system_id)
                return
            await coro(call)

        return decorator

    @callback
    def v3_only(coro):
        """Log an error if the decorated coroutine is called with a v2 system."""
        async def decorator(call):
            """Decorate."""
            system = simplisafe.systems[int(call.data[ATTR_SYSTEM_ID])]
            if system.version != 3:
                _LOGGER.error("Service only available on V3 systems")
                return
            await coro(call)

        return decorator

    @verify_system_exists
    @_verify_domain_control
    async def remove_pin(call):
        """Remove a PIN."""
        system = simplisafe.systems[call.data[ATTR_SYSTEM_ID]]
        try:
            await system.remove_pin(call.data[ATTR_PIN_LABEL_OR_VALUE])
        except SimplipyError as err:
            _LOGGER.error("Error during service call: %s", err)
            return

    @verify_system_exists
    @_verify_domain_control
    async def set_pin(call):
        """Set a PIN."""
        system = simplisafe.systems[call.data[ATTR_SYSTEM_ID]]
        try:
            await system.set_pin(call.data[ATTR_PIN_LABEL],
                                 call.data[ATTR_PIN_VALUE])
        except SimplipyError as err:
            _LOGGER.error("Error during service call: %s", err)
            return

    @verify_system_exists
    @v3_only
    @_verify_domain_control
    async def set_system_properties(call):
        """Set one or more system parameters."""
        system = simplisafe.systems[call.data[ATTR_SYSTEM_ID]]
        try:
            await system.set_properties({
                prop: value
                for prop, value in call.data.items() if prop != ATTR_SYSTEM_ID
            })
        except SimplipyError as err:
            _LOGGER.error("Error during service call: %s", err)
            return

    for service, method, schema in [
        ("remove_pin", remove_pin, SERVICE_REMOVE_PIN_SCHEMA),
        ("set_pin", set_pin, SERVICE_SET_PIN_SCHEMA),
        (
            "set_system_properties",
            set_system_properties,
            SERVICE_SET_SYSTEM_PROPERTIES_SCHEMA,
        ),
    ]:
        async_register_admin_service(hass,
                                     DOMAIN,
                                     service,
                                     method,
                                     schema=schema)

    return True
Пример #59
0
async def async_setup_platform(hass,
                               config,
                               async_add_entities,
                               discovery_info=None):
    """Set up the SyncThru component."""
    from pysyncthru import SyncThru

    if discovery_info is not None:
        _LOGGER.info("Discovered a new Samsung Printer at %s",
                     discovery_info.get(CONF_HOST))
        host = discovery_info.get(CONF_HOST)
        name = discovery_info.get(CONF_NAME, DEFAULT_NAME)
        # Main device, always added
    else:
        host = config.get(CONF_RESOURCE)
        name = config.get(CONF_NAME)
    # always pass through all of the obtained information
    monitored = DEFAULT_MONITORED_CONDITIONS

    session = aiohttp_client.async_get_clientsession(hass)

    printer = SyncThru(host, session)
    # Test if the discovered device actually is a syncthru printer
    # and fetch the available toner/drum/etc
    try:
        # No error is thrown when the device is off
        # (only after user added it manually)
        # therefore additional catches are inside the Sensor below
        await printer.update()
        supp_toner = printer.toner_status(filter_supported=True)
        supp_drum = printer.drum_status(filter_supported=True)
        supp_tray = printer.input_tray_status(filter_supported=True)
        supp_output_tray = printer.output_tray_status()
    except ValueError:
        # if an exception is thrown, printer does not support syncthru
        # and should not be set up
        # If the printer was discovered automatically, no warning or error
        # should be issued and printer should not be set up
        if discovery_info is not None:
            _LOGGER.info("Samsung printer at %s does not support SyncThru",
                         host)
            return
        # Otherwise, emulate printer that supports everything
        supp_toner = TONER_COLORS
        supp_drum = DRUM_COLORS
        supp_tray = TRAYS
        supp_output_tray = OUTPUT_TRAYS

    devices = [SyncThruMainSensor(printer, name)]

    for key in supp_toner:
        if "toner_{}".format(key) in monitored:
            devices.append(SyncThruTonerSensor(printer, name, key))
    for key in supp_drum:
        if "drum_{}".format(key) in monitored:
            devices.append(SyncThruDrumSensor(printer, name, key))
    for key in supp_tray:
        if "tray_{}".format(key) in monitored:
            devices.append(SyncThruInputTraySensor(printer, name, key))
    for key in supp_output_tray:
        if "output_tray_{}".format(key) in monitored:
            devices.append(SyncThruOutputTraySensor(printer, name, key))

    async_add_entities(devices, True)
Пример #60
0
async def get_controller(hass,
                         host,
                         username,
                         password,
                         port,
                         site,
                         verify_ssl,
                         async_callback=None):
    """Create a controller object and verify authentication."""
    sslcontext = None

    if verify_ssl:
        session = aiohttp_client.async_get_clientsession(hass)
        if isinstance(verify_ssl, str):
            sslcontext = ssl.create_default_context(cafile=verify_ssl)
    else:
        session = aiohttp_client.async_create_clientsession(
            hass, verify_ssl=verify_ssl, cookie_jar=CookieJar(unsafe=True))

    controller = aiounifi.Controller(
        host,
        username=username,
        password=password,
        port=port,
        site=site,
        websession=session,
        sslcontext=sslcontext,
        callback=async_callback,
    )

    try:
        async with async_timeout.timeout(10):
            await controller.check_unifi_os()
            await controller.login()
        return controller

    except aiounifi.Unauthorized as err:
        LOGGER.warning(
            "Connected to UniFi Network at %s but not registered: %s",
            host,
            err,
        )
        raise AuthenticationRequired from err

    except (
            asyncio.TimeoutError,
            aiounifi.BadGateway,
            aiounifi.ServiceUnavailable,
            aiounifi.RequestError,
            aiounifi.ResponseError,
    ) as err:
        LOGGER.error("Error connecting to the UniFi Network at %s: %s", host,
                     err)
        raise CannotConnect from err

    except aiounifi.LoginRequired as err:
        LOGGER.warning(
            "Connected to UniFi Network at %s but login required: %s",
            host,
            err,
        )
        raise AuthenticationRequired from err

    except aiounifi.AiounifiException as err:
        LOGGER.exception(
            "Unknown UniFi Network communication error occurred: %s", err)
        raise AuthenticationRequired from err