1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-21 03:20:01 +00:00
Files
core/homeassistant/components/vivotek/camera.py
2025-12-02 19:47:22 +01:00

194 lines
5.9 KiB
Python

"""Support for Vivotek IP Cameras."""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from libpyvivotek.vivotek import VivotekCamera
import voluptuous as vol
from homeassistant.components.camera import (
PLATFORM_SCHEMA as CAMERA_PLATFORM_SCHEMA,
Camera,
CameraEntityFeature,
)
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.const import (
CONF_AUTHENTICATION,
CONF_IP_ADDRESS,
CONF_NAME,
CONF_PASSWORD,
CONF_SSL,
CONF_USERNAME,
CONF_VERIFY_SSL,
HTTP_BASIC_AUTHENTICATION,
HTTP_DIGEST_AUTHENTICATION,
)
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import config_validation as cv, issue_registry as ir
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
)
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import VivotekConfigEntry
from .const import (
CONF_FRAMERATE,
CONF_SECURITY_LEVEL,
CONF_STREAM_PATH,
DOMAIN,
INTEGRATION_TITLE,
)
_LOGGER = logging.getLogger(__name__)
DEFAULT_CAMERA_BRAND = "VIVOTEK"
DEFAULT_NAME = "VIVOTEK Camera"
DEFAULT_EVENT_0_KEY = "event_i0_enable"
DEFAULT_FRAMERATE = 2
DEFAULT_SECURITY_LEVEL = "admin"
DEFAULT_STREAM_SOURCE = "live.sdp"
PLATFORM_SCHEMA = CAMERA_PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_IP_ADDRESS): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_AUTHENTICATION, default=HTTP_BASIC_AUTHENTICATION): vol.In(
[HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]
),
vol.Optional(CONF_SSL, default=False): cv.boolean,
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
vol.Optional(CONF_FRAMERATE, default=DEFAULT_FRAMERATE): cv.positive_int,
vol.Optional(CONF_SECURITY_LEVEL, default=DEFAULT_SECURITY_LEVEL): cv.string,
vol.Optional(CONF_STREAM_PATH, default=DEFAULT_STREAM_SOURCE): cv.string,
}
)
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Vivotek camera platform."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=config,
)
if (
result.get("type") is FlowResultType.ABORT
and result.get("reason") != "already_configured"
):
ir.async_create_issue(
hass,
DOMAIN,
f"deprecated_yaml_import_issue_{result.get('reason')}",
breaks_in_ha_version="2026.6.0",
is_fixable=False,
issue_domain=DOMAIN,
severity=ir.IssueSeverity.WARNING,
translation_key=f"deprecated_yaml_import_issue_{result.get('reason')}",
translation_placeholders={
"domain": DOMAIN,
"integration_title": INTEGRATION_TITLE,
},
)
return
ir.async_create_issue(
hass,
HOMEASSISTANT_DOMAIN,
"deprecated_yaml",
breaks_in_ha_version="2026.6.0",
is_fixable=False,
issue_domain=DOMAIN,
severity=ir.IssueSeverity.WARNING,
translation_key="deprecated_yaml",
translation_placeholders={
"domain": DOMAIN,
"integration_title": INTEGRATION_TITLE,
},
)
async def async_setup_entry(
hass: HomeAssistant,
entry: VivotekConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the component from a config entry."""
config = entry.data
creds = f"{config[CONF_USERNAME]}:{config[CONF_PASSWORD]}"
stream_source = (
f"rtsp://{creds}@{config[CONF_IP_ADDRESS]}:554/{config[CONF_STREAM_PATH]}"
)
cam_client = entry.runtime_data
if TYPE_CHECKING:
assert entry.unique_id is not None
async_add_entities(
[
VivotekCam(
cam_client,
stream_source,
entry.unique_id,
entry.options[CONF_FRAMERATE],
entry.title,
)
]
)
class VivotekCam(Camera):
"""A Vivotek IP camera."""
_attr_brand = DEFAULT_CAMERA_BRAND
_attr_supported_features = CameraEntityFeature.STREAM
def __init__(
self,
cam_client: VivotekCamera,
stream_source: str,
unique_id: str,
framerate: int,
name: str,
) -> None:
"""Initialize a Vivotek camera."""
super().__init__()
self._cam = cam_client
self._attr_frame_interval = 1 / framerate
self._attr_unique_id = unique_id
self._attr_name = name
self._stream_source = stream_source
def camera_image(
self, width: int | None = None, height: int | None = None
) -> bytes | None:
"""Return bytes of camera image."""
return self._cam.snapshot()
async def stream_source(self) -> str:
"""Return the source of the stream."""
return self._stream_source
def disable_motion_detection(self) -> None:
"""Disable motion detection in camera."""
response = self._cam.set_param(DEFAULT_EVENT_0_KEY, 0)
self._attr_motion_detection_enabled = int(response) == 1
def enable_motion_detection(self) -> None:
"""Enable motion detection in camera."""
response = self._cam.set_param(DEFAULT_EVENT_0_KEY, 1)
self._attr_motion_detection_enabled = int(response) == 1
def update(self) -> None:
"""Update entity status."""
self._attr_model = self._cam.model_name
self._attr_available = self._attr_model is not None