mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Remove deprecated YAML import from generic camera (#107992)
This commit is contained in:
parent
f48d057307
commit
4b8d8baa69
@ -8,28 +8,20 @@ import logging
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import voluptuous as vol
|
|
||||||
import yarl
|
import yarl
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import Camera, CameraEntityFeature
|
||||||
DEFAULT_CONTENT_TYPE,
|
|
||||||
PLATFORM_SCHEMA,
|
|
||||||
Camera,
|
|
||||||
CameraEntityFeature,
|
|
||||||
)
|
|
||||||
from homeassistant.components.stream import (
|
from homeassistant.components.stream import (
|
||||||
CONF_RTSP_TRANSPORT,
|
CONF_RTSP_TRANSPORT,
|
||||||
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
|
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
|
||||||
RTSP_TRANSPORTS,
|
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_AUTHENTICATION,
|
CONF_AUTHENTICATION,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
CONF_VERIFY_SSL,
|
CONF_VERIFY_SSL,
|
||||||
HTTP_BASIC_AUTHENTICATION,
|
|
||||||
HTTP_DIGEST_AUTHENTICATION,
|
HTTP_DIGEST_AUTHENTICATION,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -38,7 +30,6 @@ from homeassistant.helpers import config_validation as cv, template as template_
|
|||||||
from homeassistant.helpers.device_registry import DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.httpx_client import get_async_client
|
from homeassistant.helpers.httpx_client import get_async_client
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
||||||
|
|
||||||
from . import DOMAIN
|
from . import DOMAIN
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -47,64 +38,12 @@ from .const import (
|
|||||||
CONF_LIMIT_REFETCH_TO_URL_CHANGE,
|
CONF_LIMIT_REFETCH_TO_URL_CHANGE,
|
||||||
CONF_STILL_IMAGE_URL,
|
CONF_STILL_IMAGE_URL,
|
||||||
CONF_STREAM_SOURCE,
|
CONF_STREAM_SOURCE,
|
||||||
DEFAULT_NAME,
|
|
||||||
GET_IMAGE_TIMEOUT,
|
GET_IMAGE_TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Required(vol.Any(CONF_STILL_IMAGE_URL, CONF_STREAM_SOURCE)): cv.template,
|
|
||||||
vol.Optional(vol.Any(CONF_STILL_IMAGE_URL, CONF_STREAM_SOURCE)): cv.template,
|
|
||||||
vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION): vol.In(
|
|
||||||
[HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]
|
|
||||||
),
|
|
||||||
vol.Optional(CONF_LIMIT_REFETCH_TO_URL_CHANGE, default=False): cv.boolean,
|
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
||||||
vol.Optional(CONF_PASSWORD): cv.string,
|
|
||||||
vol.Optional(CONF_USERNAME): cv.string,
|
|
||||||
vol.Optional(CONF_CONTENT_TYPE, default=DEFAULT_CONTENT_TYPE): cv.string,
|
|
||||||
vol.Optional(CONF_FRAMERATE, default=2): vol.Any(
|
|
||||||
cv.small_float, cv.positive_int
|
|
||||||
),
|
|
||||||
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
|
|
||||||
vol.Optional(CONF_RTSP_TRANSPORT): vol.In(RTSP_TRANSPORTS),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
config: ConfigType,
|
|
||||||
async_add_entities: AddEntitiesCallback,
|
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
|
||||||
) -> None:
|
|
||||||
"""Set up a generic IP Camera."""
|
|
||||||
|
|
||||||
image = config.get(CONF_STILL_IMAGE_URL)
|
|
||||||
stream = config.get(CONF_STREAM_SOURCE)
|
|
||||||
config_new = {
|
|
||||||
CONF_NAME: config[CONF_NAME],
|
|
||||||
CONF_STILL_IMAGE_URL: image.template if image is not None else None,
|
|
||||||
CONF_STREAM_SOURCE: stream.template if stream is not None else None,
|
|
||||||
CONF_AUTHENTICATION: config.get(CONF_AUTHENTICATION),
|
|
||||||
CONF_USERNAME: config.get(CONF_USERNAME),
|
|
||||||
CONF_PASSWORD: config.get(CONF_PASSWORD),
|
|
||||||
CONF_LIMIT_REFETCH_TO_URL_CHANGE: config.get(CONF_LIMIT_REFETCH_TO_URL_CHANGE),
|
|
||||||
CONF_CONTENT_TYPE: config.get(CONF_CONTENT_TYPE),
|
|
||||||
CONF_FRAMERATE: config.get(CONF_FRAMERATE),
|
|
||||||
CONF_VERIFY_SSL: config.get(CONF_VERIFY_SSL),
|
|
||||||
}
|
|
||||||
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=config_new
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -40,12 +40,11 @@ from homeassistant.const import (
|
|||||||
HTTP_BASIC_AUTHENTICATION,
|
HTTP_BASIC_AUTHENTICATION,
|
||||||
HTTP_DIGEST_AUTHENTICATION,
|
HTTP_DIGEST_AUTHENTICATION,
|
||||||
)
|
)
|
||||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResult, UnknownFlow
|
from homeassistant.data_entry_flow import FlowResult, UnknownFlow
|
||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
from homeassistant.helpers import config_validation as cv, template as template_helper
|
from homeassistant.helpers import config_validation as cv, template as template_helper
|
||||||
from homeassistant.helpers.httpx_client import get_async_client
|
from homeassistant.helpers.httpx_client import get_async_client
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
from .camera import GenericCamera, generate_auth
|
from .camera import GenericCamera, generate_auth
|
||||||
@ -379,47 +378,6 @@ class GenericIPCamConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
errors=None,
|
errors=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_step_import(self, import_config: dict[str, Any]) -> FlowResult:
|
|
||||||
"""Handle config import from yaml."""
|
|
||||||
|
|
||||||
_LOGGER.warning(
|
|
||||||
"Loading generic IP camera via configuration.yaml is deprecated, "
|
|
||||||
"it will be automatically imported. Once you have confirmed correct "
|
|
||||||
"operation, please remove 'generic' (IP camera) section(s) from "
|
|
||||||
"configuration.yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
async_create_issue(
|
|
||||||
self.hass,
|
|
||||||
HOMEASSISTANT_DOMAIN,
|
|
||||||
f"deprecated_yaml_{DOMAIN}",
|
|
||||||
breaks_in_ha_version="2024.2.0",
|
|
||||||
is_fixable=False,
|
|
||||||
issue_domain=DOMAIN,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_yaml",
|
|
||||||
translation_placeholders={
|
|
||||||
"domain": DOMAIN,
|
|
||||||
"integration_title": "Generic IP Camera",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
# abort if we've already got this one.
|
|
||||||
if self.check_for_existing(import_config):
|
|
||||||
return self.async_abort(reason="already_exists")
|
|
||||||
# Don't bother testing the still or stream details on yaml import.
|
|
||||||
still_url = import_config.get(CONF_STILL_IMAGE_URL)
|
|
||||||
stream_url = import_config.get(CONF_STREAM_SOURCE)
|
|
||||||
name = import_config.get(
|
|
||||||
CONF_NAME,
|
|
||||||
slug(self.hass, still_url) or slug(self.hass, stream_url) or DEFAULT_NAME,
|
|
||||||
)
|
|
||||||
|
|
||||||
if CONF_LIMIT_REFETCH_TO_URL_CHANGE not in import_config:
|
|
||||||
import_config[CONF_LIMIT_REFETCH_TO_URL_CHANGE] = False
|
|
||||||
still_format = import_config.get(CONF_CONTENT_TYPE, "image/jpeg")
|
|
||||||
import_config[CONF_CONTENT_TYPE] = still_format
|
|
||||||
return self.async_create_entry(title=name, data={}, options=import_config)
|
|
||||||
|
|
||||||
|
|
||||||
class GenericOptionsFlowHandler(OptionsFlow):
|
class GenericOptionsFlowHandler(OptionsFlow):
|
||||||
"""Handle Generic IP Camera options."""
|
"""Handle Generic IP Camera options."""
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@ -11,6 +12,7 @@ import pytest
|
|||||||
import respx
|
import respx
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
|
DEFAULT_CONTENT_TYPE,
|
||||||
async_get_mjpeg_stream,
|
async_get_mjpeg_stream,
|
||||||
async_get_stream_source,
|
async_get_stream_source,
|
||||||
)
|
)
|
||||||
@ -24,8 +26,13 @@ from homeassistant.components.generic.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.components.stream.const import CONF_RTSP_TRANSPORT
|
from homeassistant.components.stream.const import CONF_RTSP_TRANSPORT
|
||||||
from homeassistant.components.websocket_api.const import TYPE_RESULT
|
from homeassistant.components.websocket_api.const import TYPE_RESULT
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT
|
from homeassistant.const import (
|
||||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, CONF_VERIFY_SSL
|
CONF_AUTHENTICATION,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_USERNAME,
|
||||||
|
CONF_VERIFY_SSL,
|
||||||
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
@ -33,6 +40,34 @@ from tests.common import Mock, MockConfigEntry
|
|||||||
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
||||||
|
|
||||||
|
|
||||||
|
async def help_setup_mock_config_entry(
|
||||||
|
hass: HomeAssistant, options: dict[str, Any], unique_id: Any | None = None
|
||||||
|
) -> MockConfigEntry:
|
||||||
|
"""Help setting up a generic camera config entry."""
|
||||||
|
entry_options = {
|
||||||
|
CONF_STILL_IMAGE_URL: options.get(CONF_STILL_IMAGE_URL),
|
||||||
|
CONF_STREAM_SOURCE: options.get(CONF_STREAM_SOURCE),
|
||||||
|
CONF_AUTHENTICATION: options.get(CONF_AUTHENTICATION),
|
||||||
|
CONF_USERNAME: options.get(CONF_USERNAME),
|
||||||
|
CONF_PASSWORD: options.get(CONF_PASSWORD),
|
||||||
|
CONF_LIMIT_REFETCH_TO_URL_CHANGE: options.get(
|
||||||
|
CONF_LIMIT_REFETCH_TO_URL_CHANGE, False
|
||||||
|
),
|
||||||
|
CONF_CONTENT_TYPE: options.get(CONF_CONTENT_TYPE, DEFAULT_CONTENT_TYPE),
|
||||||
|
CONF_FRAMERATE: options.get(CONF_FRAMERATE, 2),
|
||||||
|
CONF_VERIFY_SSL: options.get(CONF_VERIFY_SSL),
|
||||||
|
}
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain="generic",
|
||||||
|
title=options[CONF_NAME],
|
||||||
|
options=entry_options,
|
||||||
|
unique_id=unique_id,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
return entry
|
||||||
|
|
||||||
|
|
||||||
@respx.mock
|
@respx.mock
|
||||||
async def test_fetching_url(
|
async def test_fetching_url(
|
||||||
hass: HomeAssistant, hass_client: ClientSessionGenerator, fakeimgbytes_png
|
hass: HomeAssistant, hass_client: ClientSessionGenerator, fakeimgbytes_png
|
||||||
@ -40,22 +75,16 @@ async def test_fetching_url(
|
|||||||
"""Test that it fetches the given url."""
|
"""Test that it fetches the given url."""
|
||||||
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "http://example.com",
|
||||||
"camera": {
|
"username": "user",
|
||||||
"name": "config_test",
|
"password": "pass",
|
||||||
"platform": "generic",
|
"authentication": "basic",
|
||||||
"still_image_url": "http://example.com",
|
"framerate": 20,
|
||||||
"username": "user",
|
}
|
||||||
"password": "pass",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"authentication": "basic",
|
|
||||||
"framerate": 20,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
@ -84,22 +113,16 @@ async def test_image_caching(
|
|||||||
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
framerate = 5
|
framerate = 5
|
||||||
await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "http://example.com",
|
||||||
"camera": {
|
"username": "user",
|
||||||
"name": "config_test",
|
"password": "pass",
|
||||||
"platform": "generic",
|
"authentication": "basic",
|
||||||
"still_image_url": "http://example.com",
|
"framerate": framerate,
|
||||||
"username": "user",
|
}
|
||||||
"password": "pass",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"authentication": "basic",
|
|
||||||
"framerate": framerate,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
@ -154,21 +177,15 @@ async def test_fetching_without_verify_ssl(
|
|||||||
"""Test that it fetches the given url when ssl verify is off."""
|
"""Test that it fetches the given url when ssl verify is off."""
|
||||||
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "https://example.com",
|
||||||
"camera": {
|
"username": "user",
|
||||||
"name": "config_test",
|
"password": "pass",
|
||||||
"platform": "generic",
|
"verify_ssl": "false",
|
||||||
"still_image_url": "https://example.com",
|
}
|
||||||
"username": "user",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"password": "pass",
|
|
||||||
"verify_ssl": "false",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
@ -184,21 +201,15 @@ async def test_fetching_url_with_verify_ssl(
|
|||||||
"""Test that it fetches the given url when ssl verify is explicitly on."""
|
"""Test that it fetches the given url when ssl verify is explicitly on."""
|
||||||
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "https://example.com",
|
||||||
"camera": {
|
"username": "user",
|
||||||
"name": "config_test",
|
"password": "pass",
|
||||||
"platform": "generic",
|
"verify_ssl": True,
|
||||||
"still_image_url": "https://example.com",
|
}
|
||||||
"username": "user",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"password": "pass",
|
|
||||||
"verify_ssl": "true",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
@ -223,19 +234,13 @@ async def test_limit_refetch(
|
|||||||
|
|
||||||
hass.states.async_set("sensor.temp", "0")
|
hass.states.async_set("sensor.temp", "0")
|
||||||
|
|
||||||
await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": 'http://example.com/{{ states.sensor.temp.state + "a" }}',
|
||||||
"camera": {
|
"limit_refetch_to_url_change": True,
|
||||||
"name": "config_test",
|
}
|
||||||
"platform": "generic",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"still_image_url": 'http://example.com/{{ states.sensor.temp.state + "a" }}',
|
|
||||||
"limit_refetch_to_url_change": True,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
@ -350,20 +355,15 @@ async def test_stream_source_error(
|
|||||||
"""Test that the stream source has an error."""
|
"""Test that the stream source has an error."""
|
||||||
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
assert await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "http://example.com",
|
||||||
"camera": {
|
# Does not exist
|
||||||
"name": "config_test",
|
"stream_source": 'http://example.com/{{ states.sensor.temp.state + "a" }}',
|
||||||
"platform": "generic",
|
"limit_refetch_to_url_change": True,
|
||||||
"still_image_url": "http://example.com",
|
}
|
||||||
# Does not exist
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"stream_source": 'http://example.com/{{ states.sensor.temp.state + "a" }}',
|
|
||||||
"limit_refetch_to_url_change": True,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
assert await async_setup_component(hass, "stream", {})
|
assert await async_setup_component(hass, "stream", {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -397,23 +397,17 @@ async def test_setup_alternative_options(
|
|||||||
"""Test that the stream source is setup with different config options."""
|
"""Test that the stream source is setup with different config options."""
|
||||||
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
assert await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "https://example.com",
|
||||||
"camera": {
|
"authentication": "digest",
|
||||||
"name": "config_test",
|
"username": "user",
|
||||||
"platform": "generic",
|
"password": "pass",
|
||||||
"still_image_url": "https://example.com",
|
"stream_source": "rtsp://example.com:554/rtsp/",
|
||||||
"authentication": "digest",
|
"rtsp_transport": "udp",
|
||||||
"username": "user",
|
}
|
||||||
"password": "pass",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"stream_source": "rtsp://example.com:554/rtsp/",
|
|
||||||
"rtsp_transport": "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert hass.states.get("camera.config_test")
|
assert hass.states.get("camera.config_test")
|
||||||
|
|
||||||
|
|
||||||
@ -427,19 +421,13 @@ async def test_no_stream_source(
|
|||||||
"""Test a stream request without stream source option set."""
|
"""Test a stream request without stream source option set."""
|
||||||
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("https://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
assert await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "https://example.com",
|
||||||
"camera": {
|
"limit_refetch_to_url_change": True,
|
||||||
"name": "config_test",
|
}
|
||||||
"platform": "generic",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"still_image_url": "https://example.com",
|
|
||||||
"limit_refetch_to_url_change": True,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.camera.Stream.endpoint_url",
|
"homeassistant.components.camera.Stream.endpoint_url",
|
||||||
@ -494,22 +482,9 @@ async def test_camera_content_type(
|
|||||||
"framerate": 2,
|
"framerate": 2,
|
||||||
"verify_ssl": True,
|
"verify_ssl": True,
|
||||||
}
|
}
|
||||||
|
await help_setup_mock_config_entry(hass, cam_config_jpg, unique_id=12345)
|
||||||
|
await help_setup_mock_config_entry(hass, cam_config_svg, unique_id=54321)
|
||||||
|
|
||||||
result1 = await hass.config_entries.flow.async_init(
|
|
||||||
"generic",
|
|
||||||
data=cam_config_jpg,
|
|
||||||
context={"source": SOURCE_IMPORT, "unique_id": 12345},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
result2 = await hass.config_entries.flow.async_init(
|
|
||||||
"generic",
|
|
||||||
data=cam_config_svg,
|
|
||||||
context={"source": SOURCE_IMPORT, "unique_id": 54321},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert result1["type"] == "create_entry"
|
|
||||||
assert result2["type"] == "create_entry"
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
resp_1 = await client.get("/api/camera_proxy/camera.config_test_svg")
|
resp_1 = await client.get("/api/camera_proxy/camera.config_test_svg")
|
||||||
@ -538,21 +513,15 @@ async def test_timeout_cancelled(
|
|||||||
|
|
||||||
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
|
||||||
|
|
||||||
await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"still_image_url": "http://example.com",
|
||||||
"camera": {
|
"username": "user",
|
||||||
"name": "config_test",
|
"password": "pass",
|
||||||
"platform": "generic",
|
"framerate": 20,
|
||||||
"still_image_url": "http://example.com",
|
}
|
||||||
"username": "user",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"password": "pass",
|
|
||||||
"framerate": 20,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
@ -589,19 +558,13 @@ async def test_timeout_cancelled(
|
|||||||
async def test_frame_interval_property(hass: HomeAssistant) -> None:
|
async def test_frame_interval_property(hass: HomeAssistant) -> None:
|
||||||
"""Test that the frame interval is calculated and returned correctly."""
|
"""Test that the frame interval is calculated and returned correctly."""
|
||||||
|
|
||||||
await async_setup_component(
|
options = {
|
||||||
hass,
|
"name": "config_test",
|
||||||
"camera",
|
"platform": "generic",
|
||||||
{
|
"stream_source": "rtsp://example.com:554/rtsp/",
|
||||||
"camera": {
|
"framerate": 5,
|
||||||
"name": "config_test",
|
}
|
||||||
"platform": "generic",
|
await help_setup_mock_config_entry(hass, options)
|
||||||
"stream_source": "rtsp://example.com:554/rtsp/",
|
|
||||||
"framerate": 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
request = Mock()
|
request = Mock()
|
||||||
with patch(
|
with patch(
|
||||||
|
@ -34,9 +34,9 @@ from homeassistant.const import (
|
|||||||
CONF_VERIFY_SSL,
|
CONF_VERIFY_SSL,
|
||||||
HTTP_BASIC_AUTHENTICATION,
|
HTTP_BASIC_AUTHENTICATION,
|
||||||
)
|
)
|
||||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
from tests.typing import ClientSessionGenerator
|
from tests.typing import ClientSessionGenerator
|
||||||
@ -756,35 +756,6 @@ async def test_options_only_stream(
|
|||||||
assert result3["data"][CONF_CONTENT_TYPE] == "image/jpeg"
|
assert result3["data"][CONF_CONTENT_TYPE] == "image/jpeg"
|
||||||
|
|
||||||
|
|
||||||
# These below can be deleted after deprecation period is finished.
|
|
||||||
@respx.mock
|
|
||||||
async def test_import(hass: HomeAssistant, fakeimg_png) -> None:
|
|
||||||
"""Test configuration.yaml import used during migration."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=TESTDATA_YAML
|
|
||||||
)
|
|
||||||
# duplicate import should be aborted
|
|
||||||
result2 = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=TESTDATA_YAML
|
|
||||||
)
|
|
||||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
|
||||||
assert result["title"] == "Yaml Defined Name"
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
issue_registry = ir.async_get(hass)
|
|
||||||
issue = issue_registry.async_get_issue(
|
|
||||||
HOMEASSISTANT_DOMAIN, "deprecated_yaml_generic"
|
|
||||||
)
|
|
||||||
assert issue.translation_key == "deprecated_yaml"
|
|
||||||
|
|
||||||
# Any name defined in yaml should end up as the entity id.
|
|
||||||
assert hass.states.get("camera.yaml_defined_name")
|
|
||||||
assert result2["type"] == FlowResultType.ABORT
|
|
||||||
|
|
||||||
|
|
||||||
# These above can be deleted after deprecation period is finished.
|
|
||||||
|
|
||||||
|
|
||||||
async def test_unload_entry(hass: HomeAssistant, fakeimg_png) -> None:
|
async def test_unload_entry(hass: HomeAssistant, fakeimg_png) -> None:
|
||||||
"""Test unloading the generic IP Camera entry."""
|
"""Test unloading the generic IP Camera entry."""
|
||||||
mock_entry = MockConfigEntry(domain=DOMAIN, options=TESTDATA)
|
mock_entry = MockConfigEntry(domain=DOMAIN, options=TESTDATA)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user