<commit_before>"""Component to interface with cameras."""
import asyncio
import base64
import collections
from contextlib import suppress
from datetime import timedelta
import hashlib
import logging
from random import SystemRandom

from aiohttp import web
import async_timeout
import attr
import voluptuous as vol

from homeassistant.components import websocket_api
from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView
from homeassistant.components.media_player.const import (
    ATTR_MEDIA_CONTENT_ID,
    ATTR_MEDIA_CONTENT_TYPE,
    DOMAIN as DOMAIN_MP,
    SERVICE_PLAY_MEDIA,
)
from homeassistant.components.stream import request_stream
from homeassistant.components.stream.const import (
    CONF_DURATION,
    CONF_LOOKBACK,
    CONF_STREAM_SOURCE,
    DOMAIN as DOMAIN_STREAM,
    FORMAT_CONTENT_TYPE,
    OUTPUT_FORMATS,
    SERVICE_RECORD,
)
from homeassistant.const import (
    ATTR_ENTITY_ID,
    CONF_FILENAME,
    SERVICE_TURN_OFF,
    SERVICE_TURN_ON,
)
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import (  # noqa: F401
    PLATFORM_SCHEMA,
    PLATFORM_SCHEMA_BASE,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.loader import bind_hass
from homeassistant.setup import async_when_setup

from .const import DATA_CAMERA_PREFS, DOMAIN
from .prefs import CameraPreferences

# mypy: allow-untyped-calls, allow-untyped-defs

_LOGGER = logging.getLogger(__name__)

SERVICE_ENABLE_MOTION = "enable_motion_detection"
SERVICE_DISABLE_MOTION = "disable_motion_detection"
SERVICE_SNAPSHOT = "snapshot"
SERVICE_PLAY_STREAM = "play_stream"

SCAN_INTERVAL = timedelta(seconds=30)
ENTITY_ID_FORMAT = DOMAIN + ".{}"

ATTR_FILENAME = "filename"
ATTR_MEDIA_PLAYER = "media_player"
ATTR_FORMAT = "format"

STATE_RECORDING = "recording"
STATE_STREAMING = "streaming"
STATE_IDLE = "idle"

# Bitfield of features supported by the camera entity
SUPPORT_ON_OFF = 1
SUPPORT_STREAM = 2

DEFAULT_CONTENT_TYPE = "image/jpeg"
ENTITY_IMAGE_URL = "/api/camera_proxy/{0}?token={1}"

TOKEN_CHANGE_INTERVAL = timedelta(minutes=5)
_RND = SystemRandom()

MIN_STREAM_INTERVAL = 0.5  # seconds

CAMERA_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.comp_entity_ids})

CAMERA_SERVICE_SNAPSHOT = CAMERA_SERVICE_SCHEMA.extend(
    {vol.Required(ATTR_FILENAME): cv.template}
)

CAMERA_SERVICE_PLAY_STREAM = CAMERA_SERVICE_SCHEMA.extend(
    {
        vol.Required(ATTR_MEDIA_PLAYER): cv.entities_domain(DOMAIN_MP),
        vol.Optional(ATTR_FORMAT, default="hls"): vol.In(OUTPUT_FORMATS),
    }
)

CAMERA_SERVICE_RECORD = CAMERA_SERVICE_SCHEMA.extend(
    {
        vol.Required(CONF_FILENAME): cv.template,
        vol.Optional(CONF_DURATION, default=30): vol.Coerce(int),
        vol.Optional(CONF_LOOKBACK, default=0): vol.Coerce(int),
    }
)

WS_TYPE_CAMERA_THUMBNAIL = "camera_thumbnail"
SCHEMA_WS_CAMERA_THUMBNAIL = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
    {
        vol.Required("type"): WS_TYPE_CAMERA_THUMBNAIL,
        vol.Required("entity_id"): cv.entity_id,
    }
)


@attr.s
class Image:
    """Represent an image."""

    content_type = attr.ib(type=str)
    content = attr.ib(type=bytes)


@bind_hass
async def async_request_stream(hass, entity_id, fmt):
    """Request a stream for a camera entity."""
    camera = _get_camera_from_entity_id(hass, entity_id)
    camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id)

    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"
        )

    return request_stream(
        hass,
        source,
        fmt=fmt,
        keepalive=camera_prefs.preload_stream,
        options=camera.options,
    )


@bind_hass
async def async_get_image(hass, entity_id, timeout=10):
    """Fetch an image from a camera entity."""
    camera = _get_camera_from_entity_id(hass, entity_id)

    with suppress(asyncio.CancelledError, asyncio.TimeoutError):
        async with async_timeout.timeout(timeout):
            image = await camera.async_camera_image()<commit_msg>Fix camera.options to camera.stream_options. (#32767)<commit_after>"""Component to interface with cameras."""
import asyncio
import base64
import collections
from contextlib import suppress
from datetime import timedelta
import hashlib
import logging
from random import SystemRandom

from aiohttp import web
import async_timeout
import attr
import voluptuous as vol

from homeassistant.components import websocket_api
from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView
from homeassistant.components.media_player.const import (
    ATTR_MEDIA_CONTENT_ID,
    ATTR_MEDIA_CONTENT_TYPE,
    DOMAIN as DOMAIN_MP,
    SERVICE_PLAY_MEDIA,
)
from homeassistant.components.stream import request_stream
from homeassistant.components.stream.const import (
    CONF_DURATION,
    CONF_LOOKBACK,
    CONF_STREAM_SOURCE,
    DOMAIN as DOMAIN_STREAM,
    FORMAT_CONTENT_TYPE,
    OUTPUT_FORMATS,
    SERVICE_RECORD,
)
from homeassistant.const import (
    ATTR_ENTITY_ID,
    CONF_FILENAME,
    SERVICE_TURN_OFF,
    SERVICE_TURN_ON,
)
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import (  # noqa: F401
    PLATFORM_SCHEMA,
    PLATFORM_SCHEMA_BASE,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.loader import bind_hass
from homeassistant.setup import async_when_setup

from .const import DATA_CAMERA_PREFS, DOMAIN
from .prefs import CameraPreferences

# mypy: allow-untyped-calls, allow-untyped-defs

_LOGGER = logging.getLogger(__name__)

SERVICE_ENABLE_MOTION = "enable_motion_detection"
SERVICE_DISABLE_MOTION = "disable_motion_detection"
SERVICE_SNAPSHOT = "snapshot"
SERVICE_PLAY_STREAM = "play_stream"

SCAN_INTERVAL = timedelta(seconds=30)
ENTITY_ID_FORMAT = DOMAIN + ".{}"

ATTR_FILENAME = "filename"
ATTR_MEDIA_PLAYER = "media_player"
ATTR_FORMAT = "format"

STATE_RECORDING = "recording"
STATE_STREAMING = "streaming"
STATE_IDLE = "idle"

# Bitfield of features supported by the camera entity
SUPPORT_ON_OFF = 1
SUPPORT_STREAM = 2

DEFAULT_CONTENT_TYPE = "image/jpeg"
ENTITY_IMAGE_URL = "/api/camera_proxy/{0}?token={1}"

TOKEN_CHANGE_INTERVAL = timedelta(minutes=5)
_RND = SystemRandom()

MIN_STREAM_INTERVAL = 0.5  # seconds

CAMERA_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.comp_entity_ids})

CAMERA_SERVICE_SNAPSHOT = CAMERA_SERVICE_SCHEMA.extend(
    {vol.Required(ATTR_FILENAME): cv.template}
)

CAMERA_SERVICE_PLAY_STREAM = CAMERA_SERVICE_SCHEMA.extend(
    {
        vol.Required(ATTR_MEDIA_PLAYER): cv.entities_domain(DOMAIN_MP),
        vol.Optional(ATTR_FORMAT, default="hls"): vol.In(OUTPUT_FORMATS),
    }
)

CAMERA_SERVICE_RECORD = CAMERA_SERVICE_SCHEMA.extend(
    {
        vol.Required(CONF_FILENAME): cv.template,
        vol.Optional(CONF_DURATION, default=30): vol.Coerce(int),
        vol.Optional(CONF_LOOKBACK, default=0): vol.Coerce(int),
    }
)

WS_TYPE_CAMERA_THUMBNAIL = "camera_thumbnail"
SCHEMA_WS_CAMERA_THUMBNAIL = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
    {
        vol.Required("type"): WS_TYPE_CAMERA_THUMBNAIL,
        vol.Required("entity_id"): cv.entity_id,
    }
)


@attr.s
class Image:
    """Represent an image."""

    content_type = attr.ib(type=str)
    content = attr.ib(type=bytes)


@bind_hass
async def async_request_stream(hass, entity_id, fmt):
    """Request a stream for a camera entity."""
    camera = _get_camera_from_entity_id(hass, entity_id)
    camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id)

    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"
        )

    return request_stream(
        hass,
        source,
        fmt=fmt,
        keepalive=camera_prefs.preload_stream,
        options=camera.stream_options,
    )


@bind_hass
async def async_get_image(hass, entity_id, timeout=10):
    """Fetch an image from a camera entity."""
    camera = _get_camera_from_entity_id(hass, entity_id)

    with suppress(asyncio.CancelledError, asyncio.TimeoutError):
        async with async_timeout.timeout(timeout):
            image = await camera.async_camera_image()
{'fraction_non_alphanumeric': 0.08191282461960873, 'fraction_numerical': 0.0053769591579910766, 'mean_word_length': 4.774108322324967, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7476443', 'n_tokens_mistral': 2973, 'n_tokens_neox': 2933, 'n_words': 575}