async def test_setup_source(hass):
    """Check that we register sources correctly."""
    platform = MockEntityPlatform(hass)

    entity_platform = MockEntity(name="Platform Config Source")
    await platform.async_add_entities([entity_platform])

    platform.config_entry = MockConfigEntry()
    entity_entry = MockEntity(name="Config Entry Source")
    await platform.async_add_entities([entity_entry])

    assert entity.entity_sources(hass) == {
        "test_domain.platform_config_source": {
            "custom_component": False,
            "domain": "test_platform",
            "source": entity.SOURCE_PLATFORM_CONFIG,
        },
        "test_domain.config_entry_source": {
            "config_entry": platform.config_entry.entry_id,
            "custom_component": False,
            "domain": "test_platform",
            "source": entity.SOURCE_CONFIG_ENTRY,
        },
    }

    await platform.async_reset()

    assert entity.entity_sources(hass) == {}
예제 #2
0
def handle_entity_source(hass: HomeAssistant, connection: ActiveConnection,
                         msg: dict[str, Any]) -> None:
    """Handle entity source command."""
    raw_sources = entity.entity_sources(hass)
    entity_perm = connection.user.permissions.check_entity

    if "entity_id" not in msg:
        if connection.user.permissions.access_all_entities("read"):
            sources = raw_sources
        else:
            sources = {
                entity_id: source
                for entity_id, source in raw_sources.items()
                if entity_perm(entity_id, "read")
            }

        connection.send_message(messages.result_message(msg["id"], sources))
        return

    sources = {}

    for entity_id in msg["entity_id"]:
        if not entity_perm(entity_id, "read"):
            raise Unauthorized(
                context=connection.context(msg),
                permission=POLICY_READ,
                perm_category=CAT_ENTITIES,
            )

        if (source := raw_sources.get(entity_id)) is None:
            connection.send_error(msg["id"], ERR_NOT_FOUND, "Entity not found")
            return

        sources[entity_id] = source
예제 #3
0
def warn_dip(hass: HomeAssistant, entity_id: str, state: State) -> None:
    """Log a warning once if a sensor with state_class_total has a decreasing value.

    The log will be suppressed until two dips have been seen to prevent warning due to
    rounding issues with databases storing the state as a single precision float, which
    was fixed in recorder DB version 20.
    """
    if SEEN_DIP not in hass.data:
        hass.data[SEEN_DIP] = set()
    if entity_id not in hass.data[SEEN_DIP]:
        hass.data[SEEN_DIP].add(entity_id)
        return
    if WARN_DIP not in hass.data:
        hass.data[WARN_DIP] = set()
    if entity_id not in hass.data[WARN_DIP]:
        hass.data[WARN_DIP].add(entity_id)
        domain = entity_sources(hass).get(entity_id, {}).get("domain")
        if domain in ["energy", "growatt_server", "solaredge"]:
            return
        _LOGGER.warning(
            "Entity %s %shas state class total_increasing, but its state is "
            "not strictly increasing. Triggered by state %s with last_updated set to %s. "
            "Please %s",
            entity_id,
            f"from integration {domain} " if domain else "",
            state.state,
            state.last_updated.isoformat(),
            _suggest_report_issue(hass, entity_id),
        )
예제 #4
0
def _suggest_report_issue(hass: HomeAssistant, entity_id: str) -> str:
    """Suggest to report an issue."""
    domain = entity_sources(hass).get(entity_id, {}).get("domain")
    custom_component = entity_sources(hass).get(entity_id, {}).get("custom_component")
    report_issue = ""
    if custom_component:
        report_issue = "report it to the custom component author."
    else:
        report_issue = (
            "create a bug report at "
            "https://github.com/home-assistant/core/issues?q=is%3Aopen+is%3Aissue"
        )
        if domain:
            report_issue += f"+label%3A%22integration%3A+{domain}%22"

    return report_issue
예제 #5
0
def warn_dip(hass: HomeAssistant, entity_id: str) -> None:
    """Log a warning once if a sensor with state_class_total has a decreasing value.

    The log will be suppressed until two dips have been seen to prevent warning due to
    rounding issues with databases storing the state as a single precision float, which
    was fixed in recorder DB version 20.
    """
    if SEEN_DIP not in hass.data:
        hass.data[SEEN_DIP] = set()
    if entity_id not in hass.data[SEEN_DIP]:
        hass.data[SEEN_DIP].add(entity_id)
        return
    if WARN_DIP not in hass.data:
        hass.data[WARN_DIP] = set()
    if entity_id not in hass.data[WARN_DIP]:
        hass.data[WARN_DIP].add(entity_id)
        domain = entity_sources(hass).get(entity_id, {}).get("domain")
        if domain in ["energy", "growatt_server", "solaredge"]:
            return
        _LOGGER.warning(
            "Entity %s %shas state class total_increasing, but its state is "
            "not strictly increasing. Please create a bug report at %s",
            entity_id,
            f"from integration {domain} " if domain else "",
            "https://github.com/home-assistant/core/issues?q=is%3Aopen+is%3Aissue"
            "+label%3A%22integration%3A+recorder%22",
        )
예제 #6
0
async def async_handle_play_stream_service(
    camera: Camera, service_call: ServiceCall
) -> None:
    """Handle play stream services calls."""
    fmt = service_call.data[ATTR_FORMAT]
    url = await _async_stream_endpoint_url(camera.hass, camera, fmt)

    hass = camera.hass
    data: Mapping[str, str] = {
        ATTR_MEDIA_CONTENT_ID: f"{get_url(hass)}{url}",
        ATTR_MEDIA_CONTENT_TYPE: FORMAT_CONTENT_TYPE[fmt],
    }

    # It is required to send a different payload for cast media players
    entity_ids = service_call.data[ATTR_MEDIA_PLAYER]
    sources = entity_sources(hass)
    cast_entity_ids = [
        entity
        for entity in entity_ids
        # All entities should be in sources. This extra guard is to
        # avoid people writing to the state machine and breaking it.
        if entity in sources and sources[entity]["domain"] == "cast"
    ]
    other_entity_ids = list(set(entity_ids) - set(cast_entity_ids))

    if cast_entity_ids:
        await hass.services.async_call(
            DOMAIN_MP,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_ENTITY_ID: cast_entity_ids,
                **data,
                ATTR_MEDIA_EXTRA: {
                    "stream_type": "LIVE",
                    "media_info": {
                        "hlsVideoSegmentFormat": "fmp4",
                    },
                },
            },
            blocking=True,
            context=service_call.context,
        )

    if other_entity_ids:
        await hass.services.async_call(
            DOMAIN_MP,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_ENTITY_ID: other_entity_ids,
                **data,
            },
            blocking=True,
            context=service_call.context,
        )
예제 #7
0
def warn_negative(hass: HomeAssistant, entity_id: str) -> None:
    """Log a warning once if a sensor with state_class_total has a negative value."""
    if WARN_NEGATIVE not in hass.data:
        hass.data[WARN_NEGATIVE] = set()
    if entity_id not in hass.data[WARN_NEGATIVE]:
        hass.data[WARN_NEGATIVE].add(entity_id)
        domain = entity_sources(hass).get(entity_id, {}).get("domain")
        _LOGGER.warning(
            "Entity %s %shas state class total_increasing, but its state is "
            "negative. Please %s",
            entity_id,
            f"from integration {domain} " if domain else "",
            _suggest_report_issue(hass, entity_id),
        )
예제 #8
0
async def async_handle_play_stream_service(camera, service_call):
    """Handle play stream services calls."""
    fmt = service_call.data[ATTR_FORMAT]
    url = await _async_stream_endpoint_url(camera.hass, camera, fmt)

    hass = camera.hass
    data = {
        ATTR_MEDIA_CONTENT_ID: f"{get_url(hass)}{url}",
        ATTR_MEDIA_CONTENT_TYPE: FORMAT_CONTENT_TYPE[fmt],
    }

    # It is required to send a different payload for cast media players
    entity_ids = service_call.data[ATTR_MEDIA_PLAYER]
    cast_entity_ids = [
        entity
        for entity, source in entity_sources(hass).items()
        if entity in entity_ids and source["domain"] == "cast"
    ]
    other_entity_ids = list(set(entity_ids) - set(cast_entity_ids))

    if cast_entity_ids:
        await hass.services.async_call(
            DOMAIN_MP,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_ENTITY_ID: cast_entity_ids,
                **data,
                ATTR_MEDIA_EXTRA: {
                    "stream_type": "LIVE",
                    "media_info": {
                        "hlsVideoSegmentFormat": "fmp4",
                    },
                },
            },
            blocking=True,
            context=service_call.context,
        )

    if other_entity_ids:
        await hass.services.async_call(
            DOMAIN_MP,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_ENTITY_ID: other_entity_ids,
                **data,
            },
            blocking=True,
            context=service_call.context,
        )
예제 #9
0
파일: entities.py 프로젝트: jbouwh/core
    def interfaces(self):
        """Yield the supported interfaces."""
        yield AlexaPowerController(self.entity)

        supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
        if supported & media_player.MediaPlayerEntityFeature.VOLUME_SET:
            yield AlexaSpeaker(self.entity)
        elif supported & media_player.MediaPlayerEntityFeature.VOLUME_STEP:
            yield AlexaStepSpeaker(self.entity)

        playback_features = (
            media_player.MediaPlayerEntityFeature.PLAY
            | media_player.MediaPlayerEntityFeature.PAUSE
            | media_player.MediaPlayerEntityFeature.STOP
            | media_player.MediaPlayerEntityFeature.NEXT_TRACK
            | media_player.MediaPlayerEntityFeature.PREVIOUS_TRACK)
        if supported & playback_features:
            yield AlexaPlaybackController(self.entity)
            yield AlexaPlaybackStateReporter(self.entity)

        if supported & media_player.MediaPlayerEntityFeature.SEEK:
            yield AlexaSeekController(self.entity)

        if supported & media_player.MediaPlayerEntityFeature.SELECT_SOURCE:
            inputs = AlexaInputController.get_valid_inputs(
                self.entity.attributes.get(
                    media_player.const.ATTR_INPUT_SOURCE_LIST, []))
            if len(inputs) > 0:
                yield AlexaInputController(self.entity)

        if supported & media_player.MediaPlayerEntityFeature.PLAY_MEDIA:
            yield AlexaChannelController(self.entity)

        # AlexaEqualizerController is disabled for denonavr
        # since it blocks alexa from discovering any devices.
        domain = entity_sources(self.hass).get(self.entity_id,
                                               {}).get("domain")
        if (supported & media_player.MediaPlayerEntityFeature.SELECT_SOUND_MODE
                and domain != "denonavr"):
            inputs = AlexaEqualizerController.get_valid_inputs(
                self.entity.attributes.get(
                    media_player.const.ATTR_SOUND_MODE_LIST, []))
            if len(inputs) > 0:
                yield AlexaEqualizerController(self.entity)

        yield AlexaEndpointHealth(self.hass, self.entity)
        yield Alexa(self.hass)
예제 #10
0
async def async_handle_play_stream_service(camera, service_call):
    """Handle play stream services calls."""
    async with async_timeout.timeout(10):
        source = await camera.stream_source()

    if not source:
        raise HomeAssistantError(
            f"{camera.entity_id} does not support play stream service")

    hass = camera.hass
    camera_prefs = hass.data[DATA_CAMERA_PREFS].get(camera.entity_id)
    fmt = service_call.data[ATTR_FORMAT]
    entity_ids = service_call.data[ATTR_MEDIA_PLAYER]

    url = request_stream(
        hass,
        source,
        fmt=fmt,
        keepalive=camera_prefs.preload_stream,
        options=camera.stream_options,
    )
    data = {
        ATTR_MEDIA_CONTENT_ID: f"{get_url(hass)}{url}",
        ATTR_MEDIA_CONTENT_TYPE: FORMAT_CONTENT_TYPE[fmt],
    }

    # It is required to send a different payload for cast media players
    cast_entity_ids = [
        entity for entity, source in entity_sources(hass).items()
        if entity in entity_ids and source["domain"] == "cast"
    ]
    other_entity_ids = list(set(entity_ids) - set(cast_entity_ids))

    if cast_entity_ids:
        await hass.services.async_call(
            DOMAIN_MP,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_ENTITY_ID: cast_entity_ids,
                **data,
                ATTR_MEDIA_EXTRA: {
                    "stream_type": "LIVE",
                    "media_info": {
                        "hlsVideoSegmentFormat": "fmp4",
                    },
                },
            },
            blocking=True,
            context=service_call.context,
        )

    if other_entity_ids:
        await hass.services.async_call(
            DOMAIN_MP,
            SERVICE_PLAY_MEDIA,
            {
                ATTR_ENTITY_ID: other_entity_ids,
                **data,
            },
            blocking=True,
            context=service_call.context,
        )