Example #1
0
    async def get(self, request):
        """Get discovery information."""
        hass = request.app["hass"]
        uuid = await hass.helpers.instance_id.async_get()
        system_info = await async_get_system_info(hass)

        data = {
            ATTR_UUID: uuid,
            ATTR_BASE_URL: None,
            ATTR_EXTERNAL_URL: None,
            ATTR_INTERNAL_URL: None,
            ATTR_LOCATION_NAME: hass.config.location_name,
            ATTR_INSTALLATION_TYPE: system_info[ATTR_INSTALLATION_TYPE],
            # always needs authentication
            ATTR_REQUIRES_API_PASSWORD: True,
            ATTR_VERSION: __version__,
        }

        with suppress(NoURLAvailableError):
            data["external_url"] = get_url(hass, allow_internal=False)

        with suppress(NoURLAvailableError):
            data["internal_url"] = get_url(hass, allow_external=False)

        # Set old base URL based on external or internal
        data["base_url"] = data["external_url"] or data["internal_url"]

        return self.json(data)
Example #2
0
    async def async_getAppImageUrl(self, hass, appTitle):
        """Check app image is present."""
        if appTitle == self._lastAppTitle:
            return self._appImageUrl

        self._appImageUrl = None

        appImageUrl = APP_IMAGE_URL_BASE.format(appTitle.casefold())

        websession = async_get_clientsession(hass)
        base_url = get_url(hass)
        request_url = base_url + appImageUrl
        certok = False

        if self._use_internal:
            certok = await self._async_check_for_image(websession, appTitle,
                                                       appImageUrl,
                                                       request_url)
        if not self._use_internal or not certok:
            self._use_internal = False
            base_url = get_url(hass, allow_internal=False)
            request_url = base_url + appImageUrl
            certok = await self._async_check_for_image(websession, appTitle,
                                                       request_url,
                                                       request_url)

        return self._appImageUrl
    async def async_getAppImageUrl(self, hass, appTitle):
        """Check app image is present."""
        if appTitle == self._lastAppTitle:
            return self._appImageUrl

        self._appImageUrl = None

        appImageUrl = APP_IMAGE_URL_BASE + f"/{appTitle.casefold()}.png"

        websession = async_get_clientsession(hass)
        base_url = get_url(hass)
        request_url = base_url + appImageUrl
        certok = False

        if self._use_internal:
            certok = await self._async_check_for_image(websession, appTitle,
                                                       appImageUrl,
                                                       request_url)
        if not self._use_internal or not certok:
            try:
                base_url = get_url(hass, allow_internal=False)
                self._use_internal = False
                request_url = base_url + appImageUrl
                certok = await self._async_check_for_image(
                    websession, appTitle, request_url, request_url)
            except NoURLAvailableError:
                _LOGGER.error(
                    "E0010U - Base URL not found, have you configured them in HA General Settings?"
                )

        return self._appImageUrl
Example #4
0
def _register_hass_zc_service(hass, zeroconf, uuid):
    # Get instance UUID
    valid_location_name = _truncate_location_name_to_valid(
        hass.config.location_name)

    params = {
        "location_name": valid_location_name,
        "uuid": uuid,
        "version": __version__,
        "external_url": "",
        "internal_url": "",
        # Old base URL, for backward compatibility
        "base_url": "",
        # Always needs authentication
        "requires_api_password": True,
    }

    # Get instance URL's
    try:
        params["external_url"] = get_url(hass, allow_internal=False)
    except NoURLAvailableError:
        pass

    try:
        params["internal_url"] = get_url(hass, allow_external=False)
    except NoURLAvailableError:
        pass

    # Set old base URL based on external or internal
    params["base_url"] = params["external_url"] or params["internal_url"]

    host_ip = util.get_local_ip()

    try:
        host_ip_pton = socket.inet_pton(socket.AF_INET, host_ip)
    except OSError:
        host_ip_pton = socket.inet_pton(socket.AF_INET6, host_ip)

    _suppress_invalid_properties(params)

    info = ServiceInfo(
        ZEROCONF_TYPE,
        name=f"{valid_location_name}.{ZEROCONF_TYPE}",
        server=f"{uuid}.local.",
        addresses=[host_ip_pton],
        port=hass.http.server_port,
        properties=params,
    )

    _LOGGER.info("Starting Zeroconf broadcast")
    try:
        zeroconf.register_service(info)
    except NonUniqueNameException:
        _LOGGER.error(
            "Home Assistant instance with identical name present in the local network"
        )
async def _async_register_hass_zc_service(
    hass: HomeAssistant, aio_zc: HaAsyncZeroconf, uuid: str
) -> None:
    # Get instance UUID
    valid_location_name = _truncate_location_name_to_valid(
        hass.config.location_name or "Home"
    )

    params = {
        "location_name": valid_location_name,
        "uuid": uuid,
        "version": __version__,
        "external_url": "",
        "internal_url": "",
        # Old base URL, for backward compatibility
        "base_url": "",
        # Always needs authentication
        "requires_api_password": True,
    }

    # Get instance URL's
    with suppress(NoURLAvailableError):
        params["external_url"] = get_url(hass, allow_internal=False)

    with suppress(NoURLAvailableError):
        params["internal_url"] = get_url(hass, allow_external=False)

    # Set old base URL based on external or internal
    params["base_url"] = params["external_url"] or params["internal_url"]

    adapters = await network.async_get_adapters(hass)

    # Puts the default IPv4 address first in the list to preserve compatibility,
    # because some mDNS implementations ignores anything but the first announced address.
    host_ip = await async_get_source_ip(hass, target_ip=MDNS_TARGET_IP)
    host_ip_pton = None
    if host_ip:
        host_ip_pton = socket.inet_pton(socket.AF_INET, host_ip)
    address_list = _get_announced_addresses(adapters, host_ip_pton)

    _suppress_invalid_properties(params)

    info = AsyncServiceInfo(
        ZEROCONF_TYPE,
        name=f"{valid_location_name}.{ZEROCONF_TYPE}",
        server=f"{uuid}.local.",
        addresses=address_list,
        port=hass.http.server_port,
        properties=params,
    )

    _LOGGER.info("Starting Zeroconf broadcast")
    await aio_zc.async_register_service(info, allow_name_change=True)
Example #6
0
    def new_media_status(self, media_status):
        """Handle updates of the media status."""
        if (media_status and media_status.player_is_idle
                and media_status.idle_reason == "ERROR"):
            external_url = None
            internal_url = None
            tts_base_url = None
            url_description = ""
            if "tts" in self.hass.config.components:
                try:
                    tts_base_url = self.hass.components.tts.get_base_url(
                        self.hass)
                except KeyError:
                    # base_url not configured, ignore
                    pass
            try:
                external_url = get_url(self.hass, allow_internal=False)
            except NoURLAvailableError:
                # external_url not configured, ignore
                pass
            try:
                internal_url = get_url(self.hass, allow_external=False)
            except NoURLAvailableError:
                # internal_url not configured, ignore
                pass

            if media_status.content_id:
                if tts_base_url and media_status.content_id.startswith(
                        tts_base_url):
                    url_description = f" from tts.base_url ({tts_base_url})"
                if external_url and media_status.content_id.startswith(
                        external_url):
                    url_description = f" from external_url ({external_url})"
                if internal_url and media_status.content_id.startswith(
                        internal_url):
                    url_description = f" from internal_url ({internal_url})"

            _LOGGER.error(
                "Failed to cast media %s%s. Please make sure the URL is: "
                "Reachable from the cast device and either a publicly resolvable "
                "hostname or an IP address",
                media_status.content_id,
                url_description,
            )

        self.media_status = media_status
        self.media_status_received = dt_util.utcnow()
        self.schedule_update_ha_state()
Example #7
0
    async def set_state(self, data: RequestData,
                        state: dict[str, Any]) -> dict[str, Any] | None:
        entity_id = self.state.entity_id
        stream = await self._async_request_stream(entity_id)

        if self._config.use_cloud_stream:
            cloud_stream = self.hass.data[DOMAIN][CLOUD_STREAMS].get(entity_id)
            if not cloud_stream:
                cloud_stream = CloudStream(self.hass, stream,
                                           async_get_clientsession(self.hass))
                self.hass.data[DOMAIN][CLOUD_STREAMS][entity_id] = cloud_stream

            await cloud_stream.start()
            stream_url = cloud_stream.stream_url
        else:
            try:
                external_url = network.get_url(self.hass, allow_internal=False)
            except network.NoURLAvailableError:
                raise SmartHomeError(
                    ERR_NOT_SUPPORTED_IN_CURRENT_MODE,
                    'Unable to get Home Assistant external URL. Have you set external URLs in Configuration -> General?'
                )

            endpoint_url = stream.endpoint_url(VIDEO_STREAM_FORMAT)
            stream_url = f'{external_url}{endpoint_url}'

        return {'stream_url': stream_url, 'protocol': 'hls'}
Example #8
0
    async def async_resolve_media(self, item: MediaSourceItem) -> PlayMedia:
        """Resolve media to a url."""
        parsed = URL(item.identifier)
        if "message" not in parsed.query:
            raise Unresolvable("No message specified.")

        options = dict(parsed.query)
        kwargs: dict[str, Any] = {
            "engine": parsed.name,
            "message": options.pop("message"),
            "language": options.pop("language", None),
            "options": options,
        }
        if "cache" in options:
            kwargs["cache"] = options.pop("cache") == "true"

        manager: SpeechManager = self.hass.data[DOMAIN]

        try:
            url = await manager.async_get_url_path(**kwargs)
        except HomeAssistantError as err:
            raise Unresolvable(str(err)) from err

        mime_type = mimetypes.guess_type(url)[0] or "audio/mpeg"

        if manager.base_url and manager.base_url != get_url(self.hass):
            url = f"{manager.base_url}{url}"

        return PlayMedia(url, mime_type)
Example #9
0
def setup(hass, config):
    # 没有配置和已经运行则不操作
    if DOMAIN not in config or DOMAIN in hass.data:
        return True    
    # 默认使用自定义的外部链接
    base_url = get_url(hass).strip('/')
    # 显示插件信息
    _LOGGER.info('''
-------------------------------------------------------------------
    QQ邮箱通知插件【作者QQ:635147515】
    
    版本:''' + VERSION + '''

    API地址:''' + URL + '''

    HA地址:''' + base_url + '''
        
    项目地址:https://github.com/shaonianzhentan/ha_qqmail
-------------------------------------------------------------------''')
    # 读取配置    
    cfg  = config[DOMAIN]
    _qq = str(cfg.get('qq')) + '@qq.com'
    _code = cfg.get('code')
    # 定义QQ邮箱实例
    qm = QQMail(hass, _qq, _code, base_url + URL)
    hass.data[DOMAIN] = qm
    # 设置QQ邮箱通知服务
    if hass.services.has_service(DOMAIN, 'notify') == False:
        hass.services.async_register(DOMAIN, 'notify', qm.notify)
    # 注册静态目录
    hass.http.register_static_path(ROOT_PATH, hass.config.path('custom_components/' + DOMAIN + '/local'), False)    
    # 注册事件网关
    hass.http.register_view(HassGateView)
    return True
Example #10
0
    async def subscribe(self, event_id):
        """Subscribe to motion events and set the webhook as callback."""
        self._event_id = event_id
        self._webhook_id = await self.register_webhook()
        self._webhook_url = "{}{}".format(
            get_url(self._hass, prefer_external=False),
            self._hass.components.webhook.async_generate_path(
                self._webhook_id),
        )

        self._sman = Manager(self._host, self._port, self._username,
                             self._password)
        if await self._sman.subscribe(self._webhook_url):
            _LOGGER.info(
                "Host %s subscribed successfully to webhook %s",
                self._host,
                self._webhook_url,
            )
            await self.set_available(True)
        else:
            _LOGGER.error(
                "Host %s subscription failed to its webhook, base object state will be set to NotAvailable",
                self._host,
            )
            await self.set_available(False)
        return True
Example #11
0
    async def async_play_media(self, media_type: str, media_id: str,
                               **kwargs) -> None:
        """Play media from a URL or file, launch an application, or tune to a channel."""
        extra: dict[str, Any] = kwargs.get(ATTR_MEDIA_EXTRA) or {}

        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(
                self.hass, media_id)
            media_type = MEDIA_TYPE_URL
            media_id = sourced_media.url

        # Sign and prefix with URL if playing a relative URL
        if media_id[0] == "/":
            media_id = async_sign_path(
                self.hass,
                quote(media_id),
                dt.timedelta(seconds=media_source.DEFAULT_EXPIRY_TIME),
            )

            # prepend external URL
            hass_url = get_url(self.hass)
            media_id = f"{hass_url}{media_id}"

        if media_type not in PLAY_MEDIA_SUPPORTED_TYPES:
            _LOGGER.error(
                "Invalid media type %s. Only %s, %s, %s, and camera HLS streams are supported",
                media_type,
                MEDIA_TYPE_APP,
                MEDIA_TYPE_CHANNEL,
                MEDIA_TYPE_URL,
            )
            return

        if media_type == MEDIA_TYPE_APP:
            params = {
                param: extra[attr]
                for attr, param in ATTRS_TO_LAUNCH_PARAMS.items()
                if attr in extra
            }

            await self.coordinator.roku.launch(media_id, params)
        elif media_type == MEDIA_TYPE_CHANNEL:
            await self.coordinator.roku.tune(media_id)
        elif media_type == MEDIA_TYPE_URL:
            params = {
                param: extra[attr]
                for (attr, param) in ATTRS_TO_PLAY_VIDEO_PARAMS.items()
                if attr in extra
            }

            await self.coordinator.roku.play_on_roku(media_id, params)
        elif media_type == FORMAT_CONTENT_TYPE[HLS_PROVIDER]:
            params = {
                "MediaType": "hls",
            }

            await self.coordinator.roku.play_on_roku(media_id, params)

        await self.coordinator.async_request_refresh()
Example #12
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play a piece of media."""
        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(
                self.hass, media_id)
            media_type = sourced_media.mime_type
            media_id = sourced_media.url

        # If media ID is a relative URL, we serve it from HA.
        # Create a signed path.
        if media_id[0] == "/":
            # Sign URL with Safegate Pro Cast User
            config_entry_id = self.registry_entry.config_entry_id
            config_entry = self.hass.config_entries.async_get_entry(
                config_entry_id)
            user_id = config_entry.data["user_id"]
            user = await self.hass.auth.async_get_user(user_id)
            if user.refresh_tokens:
                refresh_token: RefreshToken = list(
                    user.refresh_tokens.values())[0]

                media_id = async_sign_path(
                    self.hass,
                    refresh_token.id,
                    quote(media_id),
                    timedelta(seconds=media_source.DEFAULT_EXPIRY_TIME),
                )

            # prepend external URL
            hass_url = get_url(self.hass, prefer_external=True)
            media_id = f"{hass_url}{media_id}"

        await self.hass.async_add_executor_job(
            ft.partial(self.play_media, media_type, media_id, **kwargs))
Example #13
0
    async def sync_serialize(self, agent_user_id):
        """Serialize entity for a SYNC response.

        https://developers.google.com/actions/smarthome/create-app#actiondevicessync
        """
        state = self.state

        entity_config = self.config.entity_config.get(state.entity_id, {})
        name = (entity_config.get(CONF_NAME) or state.name).strip()
        domain = state.domain
        device_class = state.attributes.get(ATTR_DEVICE_CLASS)
        entity_entry, device_entry = await _get_entity_and_device(
            self.hass, state.entity_id
        )

        traits = self.traits()

        device_type = get_google_type(domain, device_class)

        device = {
            "id": state.entity_id,
            "name": {"name": name},
            "attributes": {},
            "traits": [trait.name for trait in traits],
            "willReportState": self.config.should_report_state,
            "type": device_type,
        }

        # use aliases
        aliases = entity_config.get(CONF_ALIASES)
        if aliases:
            device["name"]["nicknames"] = [name] + aliases

        if self.config.is_local_sdk_active and self.should_expose_local():
            device["otherDeviceIds"] = [{"deviceId": self.entity_id}]
            device["customData"] = {
                "webhookId": self.config.local_sdk_webhook_id,
                "httpPort": self.hass.http.server_port,
                "httpSSL": self.hass.config.api.use_ssl,
                "uuid": await self.hass.helpers.instance_id.async_get(),
                "baseUrl": get_url(self.hass, prefer_external=True),
                "proxyDeviceId": agent_user_id,
            }

        for trt in traits:
            device["attributes"].update(trt.sync_attributes())

        room = entity_config.get(CONF_ROOM_HINT)
        if room:
            device["roomHint"] = room
        else:
            area = await _get_area(self.hass, entity_entry, device_entry)
            if area and area.name:
                device["roomHint"] = area.name

        device_info = await _get_device_info(device_entry)
        if device_info:
            device["deviceInfo"] = device_info

        return device
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play a piece of media."""
        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(self.hass, media_id)
            media_type = sourced_media.mime_type
            media_id = sourced_media.url

        # If media ID is a relative URL, we serve it from HA.
        # Create a signed path.
        if media_id[0] == "/":
            # Sign URL with Home Assistant Cast User
            config_entries = self.hass.config_entries.async_entries(CAST_DOMAIN)
            user_id = config_entries[0].data["user_id"]
            user = await self.hass.auth.async_get_user(user_id)
            if user.refresh_tokens:
                refresh_token: RefreshToken = list(user.refresh_tokens.values())[0]

                media_id = async_sign_path(
                    self.hass,
                    refresh_token.id,
                    media_id,
                    timedelta(minutes=5),
                )

            # prepend external URL
            hass_url = get_url(self.hass, prefer_external=True)
            media_id = f"{hass_url}{media_id}"

        await self.hass.async_add_executor_job(
            ft.partial(self.play_media, media_type, media_id, **kwargs)
        )
Example #15
0
    async def post(self, request: web.Request) -> web.Response:
        """Generate speech and provide url."""
        try:
            data = await request.json()
        except ValueError:
            return self.json_message("Invalid JSON specified", HTTPStatus.BAD_REQUEST)
        if not data.get(ATTR_PLATFORM) and data.get(ATTR_MESSAGE):
            return self.json_message(
                "Must specify platform and message", HTTPStatus.BAD_REQUEST
            )

        p_type = data[ATTR_PLATFORM]
        message = data[ATTR_MESSAGE]
        cache = data.get(ATTR_CACHE)
        language = data.get(ATTR_LANGUAGE)
        options = data.get(ATTR_OPTIONS)

        try:
            path = await self.tts.async_get_url_path(
                p_type, message, cache=cache, language=language, options=options
            )
        except HomeAssistantError as err:
            _LOGGER.error("Error on init tts: %s", err)
            return self.json({"error": err}, HTTPStatus.BAD_REQUEST)

        base = self.tts.base_url or get_url(self.tts.hass)
        url = base + path

        return self.json({"url": url, "path": path})
Example #16
0
def get_local_ip_from_internal_url(hass: HomeAssistant):
    """Get the stream ip address from the internal_url."""
    try:
        url = get_url(
            hass,
            allow_internal=True,
            allow_external=False,
            allow_cloud=False,
            allow_ip=True,
        )
    except NoURLAvailableError:
        LOGGER.warning(
            "Unable to retrieve the internal URL from Home Assistant, "
            "this may cause issues resolving the correct internal stream ip. "
            "Please set a valid internal url in the Home Assistant configuration"
        )
        return hass.config.api.local_ip
    parsed_uri = urlparse(url)

    if parsed_uri.netloc == "":
        return hass.config.api.local_ip

    try:
        return socket.gethostbyname(parsed_uri.netloc)
    except socket.gaierror:
        # url is set as ip instead of hostname
        return hass.config.api.local_ip
Example #17
0
        async def async_say_handle(service):
            """Service handle for say."""
            entity_ids = service.data[ATTR_ENTITY_ID]
            message = service.data.get(ATTR_MESSAGE)
            cache = service.data.get(ATTR_CACHE)
            language = service.data.get(ATTR_LANGUAGE)
            options = service.data.get(ATTR_OPTIONS)

            try:
                url = await tts.async_get_url_path(
                    p_type, message, cache=cache, language=language, options=options
                )
            except HomeAssistantError as err:
                _LOGGER.error("Error on init TTS: %s", err)
                return

            base = tts.base_url or get_url(hass)
            url = base + url

            data = {
                ATTR_MEDIA_CONTENT_ID: url,
                ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_MUSIC,
                ATTR_ENTITY_ID: entity_ids,
            }

            await hass.services.async_call(
                DOMAIN_MP,
                SERVICE_PLAY_MEDIA,
                data,
                blocking=True,
                context=service.context,
            )
Example #18
0
def valid_external_url(hass: HomeAssistant) -> bool:
    """Return whether a valid external URL for HA is available."""
    try:
        get_url(hass, allow_internal=False, prefer_cloud=True)
        return True
    except NoURLAvailableError:
        _LOGGER.error(
            "You do not have an external URL for your Home Assistant instance "
            "configured which is needed to set up the Zoom integration. "
            "You need to set the `external_url` property in the "
            "`homeassistant` section of your `configuration.yaml`, or set the "
            "`External URL` property in the Home Assistant `General "
            "Configuration` UI, before trying to setup the Zoom integration "
            "again. You can learn more about configuring this parameter at "
            "https://www.home-assistant.io/docs/configuration/basic")
        return False
Example #19
0
    def get_local_media_list(self, search_type):
        file_path = ''
        singer = "默认列表"
        if search_type != 'library_music':
            file_path = search_type.replace('library_', '')
            singer = file_path

        hass = self.hass
        children = []
        base_url = get_url(hass).strip('/')
        path = hass.config.path("media/ha_cloud_music")
        file_path = file_path.replace('library_', '')
        # 获取所有文件
        file_dir = os.path.join(path, file_path)
        for filename in os.listdir(file_dir):
            if os.path.isfile(os.path.join(file_dir,
                                           filename)) and '.mp3' in filename:
                songid = f"{base_url}/media-local/"
                if file_path != '':
                    songid += urllib.parse.quote(f"{file_path}/{filename}")
                else:
                    songid += urllib.parse.quote(filename)
                song = filename.replace('.mp3', '')
                children.append({
                    "name": song,
                    "song": song,
                    "singer": singer,
                    "album": "媒体库",
                    "image": f"{base_url}/static/icons/favicon-192x192.png",
                    "type": "url",
                    "url": songid
                })
        return children
Example #20
0
    async def put(self, request):
        hass = request.app["hass"]
        query = request.query
        tts_path = hass.config.path("tts/")
        try:
            # 读取文件
            reader = await request.multipart()
            file = await reader.next()
            filename = f"voice-{uuid1()}.mp3"
            size = 0
            with open(f"{tts_path}{filename}", 'wb') as f:
                while True:
                    chunk = await file.read_chunk()  # 默认是8192个字节。
                    if not chunk:
                        break
                    size += len(chunk)
                    f.write(chunk)

            # 播放音频
            source = query.get('source', '')
            if source == '':
                mp = hass.data[DOMAIN]
                await mp.api_tts.speak(filename)
            # 本地URL
            local_url = get_url(hass).strip('/') + '/tts-local/' + filename
            return self.json({'code': 0, 'msg': '发送成功', 'data': local_url})
        except Exception as e:
            return self.json({'code': 1, 'msg': '出现异常'})
Example #21
0
def get_url(hass):
  """Gets the required Home-Assistant URL for validation.

  Args:
    hass: Hass instance.

  Returns:
    Home-Assistant URL.
  """
  if network:
    try:
      return network.get_url(
          hass,
          allow_external=True,
          allow_internal=True,
          allow_ip=True,
          prefer_external=True,
          require_ssl=False)
    except AttributeError:
      logging.debug(
          'Hass version does not have get_url helper, using fall back.')

  base_url = hass.config.api.base_url
  if base_url:
    return base_url

  raise ValueError('Unable to obtain HASS url.')
Example #22
0
    async def async_play_media(self, media_type: str, media_id: str,
                               **kwargs: Any) -> None:
        """Play media from a URL or file."""
        # Handle media_source
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(
                self.hass, media_id)
            media_type = MEDIA_TYPE_MUSIC
            media_id = sourced_media.url

        # Sign and prefix with URL if playing a relative URL
        if media_id[0] == "/":
            media_id = async_sign_path(
                self.hass,
                quote(media_id),
                timedelta(seconds=media_source.DEFAULT_EXPIRY_TIME),
            )

            # prepend external URL
            hass_url = get_url(self.hass)
            media_id = f"{hass_url}{media_id}"

        if media_type != MEDIA_TYPE_MUSIC:
            LOGGER.error(
                "Invalid media type %s. Only %s is supported",
                media_type,
                MEDIA_TYPE_MUSIC,
            )
            return

        await self._vlc.add(media_id)
        self._state = STATE_PLAYING
Example #23
0
async def async_api_initialize_camera_stream(hass, config, directive, context):
    """Process a InitializeCameraStreams request."""
    entity = directive.entity
    stream_source = await camera.async_request_stream(hass, entity.entity_id, fmt="hls")
    camera_image = hass.states.get(entity.entity_id).attributes["entity_picture"]

    try:
        external_url = network.get_url(
            hass,
            allow_internal=False,
            allow_ip=False,
            require_ssl=True,
            require_standard_port=True,
        )
    except network.NoURLAvailableError:
        raise AlexaInvalidValueError("Failed to find suitable URL to serve to Alexa")

    payload = {
        "cameraStreams": [
            {
                "uri": f"{external_url}{stream_source}",
                "protocol": "HLS",
                "resolution": {"width": 1280, "height": 720},
                "authorizationType": "NONE",
                "videoCodec": "H264",
                "audioCodec": "AAC",
            }
        ],
        "imageUri": f"{external_url}{camera_image}",
    }
    return directive.response(
        name="Response", namespace="Alexa.CameraStreamController", payload=payload
    )
Example #24
0
def async_generate_motioneye_webhook(hass: HomeAssistant,
                                     webhook_id: str) -> str:
    """Generate the full local URL for a webhook_id."""
    return "{}{}".format(
        get_url(hass, allow_cloud=False),
        async_generate_path(webhook_id),
    )
Example #25
0
def setup(hass, config):
    # 显示插件信息
    _LOGGER.info('''
-------------------------------------------------------------------
    QQ邮箱通知插件【作者QQ:635147515】
    
    版本:''' + VERSION + '''

    API地址:''' + URL + '''
        
    项目地址:https://github.com/shaonianzhentan/ha_qqmail
-------------------------------------------------------------------''')
    # 注册静态目录
    local = hass.config.path('custom_components/' + DOMAIN + '/local')
    if os.path.isdir(local):
        hass.http.register_static_path(ROOT_PATH, local, False)
    # 读取配置
    cfg = config[DOMAIN]
    _qq = str(cfg.get('qq')) + '@qq.com'
    _code = cfg.get('code')

    base_url = get_url(hass)
    # 定义QQ邮箱实例
    qm = QQMail(hass, _qq, _code, base_url.strip('/') + URL)
    # 设置QQ邮箱通知服务
    if hass.services.has_service(DOMAIN, 'notify') == False:
        hass.services.register(DOMAIN, 'notify', qm.notify)
    # 注册事件网关
    hass.http.register_view(HassGateView)
    return True
Example #26
0
    async def subscribe(self, event_id):
        """Subscribe to motion events and set the webhook as callback."""
        global warnedAboutNoURLAvailableError
        self._event_id = event_id
        self._webhook_id = await self.register_webhook()

        try:
            self._webhook_url = "{}{}".format(
                get_url(self._hass, prefer_external=False),
                self._hass.components.webhook.async_generate_path(
                    self._webhook_id),
            )
        except NoURLAvailableError as ex:
            if not warnedAboutNoURLAvailableError:
                warnedAboutNoURLAvailableError = True
                _LOGGER.warning(
                    "Your are using HTTP for internal URL while using HTTPS for external URL in HA which is"
                    " not supported anymore by HomeAssistant starting 2022.3."
                    "Please change your configuration to use HTTPS for internal URL or disable HTTPS for external."
                )
            try:
                self._webhook_url = "{}{}".format(
                    get_url(self._hass, prefer_external=True),
                    self._hass.components.webhook.async_generate_path(
                        self._webhook_id),
                )
            except NoURLAvailableError as ex:
                # If we can't get a URL for external or internal, we will still mark the camara as available
                await self.set_available(True)
                return True

        self._sman = Manager(self._host, self._port, self._username,
                             self._password)
        if await self._sman.subscribe(self._webhook_url):
            _LOGGER.info(
                "Host %s subscribed successfully to webhook %s",
                self._host,
                self._webhook_url,
            )
            await self.set_available(True)
        else:
            _LOGGER.error(
                "Host %s subscription failed to its webhook, base object state will be set to NotAvailable",
                self._host,
            )
            await self.set_available(False)
        return True
Example #27
0
    async def async_play_media(self, media_type, media_id, **kwargs):
        """Play media from media_source."""
        if media_source.is_media_source_id(media_id):
            sourced_media = await media_source.async_resolve_media(self.hass, media_id)
            media_type = sourced_media.mime_type
            media_id = sourced_media.url

            # If media ID is a relative URL, we serve it from HA.
            if media_id[0] == "/":
                user = await self.hass.auth.async_get_owner()
                if user.refresh_tokens:
                    refresh_token: RefreshToken = list(user.refresh_tokens.values())[0]

                    # Use kwargs so it works both before and after the change in Home Assistant 2022.2
                    media_id = async_sign_path(
                        hass=self.hass,
                        refresh_token_id=refresh_token.id,
                        path=media_id,
                        expiration=timedelta(minutes=5)
                    )

                # Prepend external URL.
                hass_url = get_url(self.hass, allow_internal=True)
                media_id = f"{hass_url}{media_id}"

            _LOGGER.info("Meural device %s: Playing media. Media type is %s, previewing image from %s", self.name, media_type, media_id)
            await self.local_meural.send_postcard(media_id, media_type)

        # Play gallery (playlist or album) by ID.
        elif media_type in ['playlist']:
            _LOGGER.info("Meural device %s: Playing media. Media type is %s, playing gallery %s", self.name, media_type, media_id)
            await self.local_meural.send_change_gallery(media_id)

        # "Preview image from URL.
        elif media_type in [ 'image/jpg', 'image/png', 'image/jpeg' ]:
            _LOGGER.info("Meural device %s: Playing media. Media type is %s, previewing image from %s", self.name, media_type, media_id)
            await self.local_meural.send_postcard(media_id, media_type)

        # Play item (artwork) by ID. Play locally if item is in currently displayed gallery. If not, play using Meural server."""
        elif media_type in ['item']:
            if media_id.isdigit():
                currentgallery_id = self._gallery_status["current_gallery"]
                currentitems = await self.local_meural.send_get_items_by_gallery(currentgallery_id)
                in_playlist = next((g["title"] for g in currentitems if g["id"] == media_id), None)
                if in_playlist is None:
                    _LOGGER.info("Meural device %s: Playing media. Item %s is not in current gallery, trying to display via Meural server", self.name, media_id)
                    try:
                        await self.meural.device_load_item(self.meural_device_id, media_id)
                    except:
                        _LOGGER.error("Meural device %s: Playing media. Error while trying to display %s item %s via Meural server", self.name, media_type, media_id, exc_info=True)
                else:
                    _LOGGER.info("Meural device %s: Playing media. Item %s is in current gallery %s, trying to display via local device", self.name, media_id, self._gallery_status["current_gallery_name"])
                    await self.local_meural.send_change_item(media_id)
            else:
                _LOGGER.error("Meural device %s: Playing media. ID %s is not an item", self.name, media_id)

        # This is an unsupported media type.
        else:
            _LOGGER.error("Meural device %s: Playing media. Does not support displaying this %s media with ID %s", self.name, media_type, media_id)
Example #28
0
async def async_setup_platform(hass, config):
    """Set up the Telegram webhooks platform."""

    bot = initialize_bot(config)

    current_status = await hass.async_add_executor_job(bot.getWebhookInfo)
    if not (base_url := config.get(CONF_URL)):
        base_url = get_url(hass, require_ssl=True, allow_internal=False)
Example #29
0
def async_process_play_media_url(
    hass: HomeAssistant,
    media_content_id: str,
    *,
    allow_relative_url: bool = False,
    for_supervisor_network: bool = False,
) -> str:
    """Update a media URL with authentication if it points at Home Assistant."""
    parsed = yarl.URL(media_content_id)

    if parsed.scheme and parsed.scheme not in ("http", "https"):
        return media_content_id

    if parsed.is_absolute():
        if not is_hass_url(hass, media_content_id):
            return media_content_id
    else:
        if media_content_id[0] != "/":
            raise ValueError("URL is relative, but does not start with a /")

    if parsed.query:
        logging.getLogger(__name__).debug(
            "Not signing path for content with query param"
        )
    elif parsed.path.startswith(PATHS_WITHOUT_AUTH):
        # We don't sign this path if it doesn't need auth. Although signing itself can't hurt,
        # some devices are unable to handle long URLs and the auth signature might push it over.
        pass
    else:
        signed_path = async_sign_path(
            hass,
            quote(parsed.path),
            timedelta(seconds=CONTENT_AUTH_EXPIRY_TIME),
        )
        media_content_id = str(parsed.join(yarl.URL(signed_path)))

    # convert relative URL to absolute URL
    if not parsed.is_absolute() and not allow_relative_url:
        base_url = None
        if for_supervisor_network:
            base_url = get_supervisor_network_url(hass)

        if not base_url:
            try:
                base_url = get_url(hass)
            except NoURLAvailableError as err:
                msg = "Unable to determine Home Assistant URL to send to device"
                if (
                    hass.config.api
                    and hass.config.api.use_ssl
                    and (not hass.config.external_url or not hass.config.internal_url)
                ):
                    msg += ". Configure internal and external URL in general settings."
                raise HomeAssistantError(msg) from err

        media_content_id = f"{base_url}{media_content_id}"

    return media_content_id
Example #30
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Reolink from a config entry."""

    hass.data.setdefault(DOMAIN, {})

    base = ReolinkBase(
        hass,
        entry.data,
        entry.options
    )

    base.sync_functions.append(entry.add_update_listener(update_listener))

    if not await base.connect_api():
        return False

    webhook_id = await register_webhook(hass, base.event_id)
    webhook_url = "{}{}".format(
      get_url(hass, prefer_external=False),
      hass.components.webhook.async_generate_path(webhook_id)
    )

    await base.subscribe(webhook_url)

    hass.data[DOMAIN][entry.entry_id] = {BASE: base}

    async def async_update_data():
        """Perform the actual updates."""

        async with async_timeout.timeout(base.timeout):
            await base.renew()
            await base.update_states()

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

    # Fetch initial data so we have data when entities subscribe
    await coordinator.async_refresh()

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

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

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, base.stop())

    return True