mirror of
https://github.com/home-assistant/core.git
synced 2025-08-07 06:35:10 +02:00
hookid : isort fix
This commit is contained in:
276
homeassistant/components/ezviz/camera.py
Normal file
276
homeassistant/components/ezviz/camera.py
Normal file
@@ -0,0 +1,276 @@
|
||||
"""This component provides basic support for Ezviz IP cameras."""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from haffmpeg.tools import IMAGE_JPEG, ImageFrame
|
||||
from pyezviz.client import EzvizClient, PyEzvizError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.camera import PLATFORM_SCHEMA, SUPPORT_STREAM, Camera
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_CAMERAS = "cameras"
|
||||
CONF_SERIAL = "serial"
|
||||
CONF_DEFAULT_CAMERA_USERNAME = "admin"
|
||||
|
||||
DATA_FFMPEG = "ffmpeg"
|
||||
|
||||
CAMERAS_CONFIG = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_USERNAME, default=CONF_DEFAULT_CAMERA_USERNAME): cv.string,
|
||||
vol.Optional(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_SERIAL): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_CAMERAS, default={}): vol.All(),
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the Ezviz IP Cameras."""
|
||||
conf_cameras = {}
|
||||
if CONF_CAMERAS in config:
|
||||
conf_cameras = config[CONF_CAMERAS]
|
||||
_LOGGER.debug("Expecting %s cameras from config", len(conf_cameras))
|
||||
|
||||
account = config[CONF_USERNAME]
|
||||
password = config[CONF_PASSWORD]
|
||||
|
||||
try:
|
||||
ezviz_client = EzvizClient(account, password)
|
||||
ezviz_client.login()
|
||||
|
||||
# Get cameras
|
||||
connections = ezviz_client.get_CONNECTION()
|
||||
devices = ezviz_client.get_DEVICE()
|
||||
# now, let's build the HASS devices
|
||||
cameras = {}
|
||||
for device in devices:
|
||||
|
||||
device_serial = device["deviceSerial"]
|
||||
|
||||
# There seem to be a bug related to localRtspPort in Ezviz API...
|
||||
local_rtsp_port = 554
|
||||
if connections[device_serial]["localRtspPort"] != 0:
|
||||
local_rtsp_port = connections[device_serial]["localRtspPort"]
|
||||
|
||||
cameras[device_serial] = {
|
||||
"serial": device_serial,
|
||||
"name": device["name"],
|
||||
"deviceType": device["deviceType"],
|
||||
"version": device["version"],
|
||||
"status": device["status"],
|
||||
"createTime": device["userDeviceCreateTime"],
|
||||
"category": device["deviceCategory"],
|
||||
"subCategory": device["deviceSubCategory"],
|
||||
"customType": device["customType"],
|
||||
"localIp": connections[device_serial]["localIp"],
|
||||
"netIp": connections[device_serial]["netIp"],
|
||||
"localRtspPort": local_rtsp_port,
|
||||
"netType": connections[device_serial]["netType"],
|
||||
"wanIp": connections[device_serial]["wanIp"],
|
||||
}
|
||||
|
||||
# Add the cameras as devices in HASS
|
||||
for camera_serial in cameras:
|
||||
camera = cameras[camera_serial]
|
||||
_LOGGER.debug("CAMERA: %s", camera)
|
||||
|
||||
camera_username = CONF_DEFAULT_CAMERA_USERNAME
|
||||
camera_password = ""
|
||||
camera_rtsp_stream = ""
|
||||
|
||||
if camera_serial in conf_cameras:
|
||||
camera_username = conf_cameras[camera_serial]["username"]
|
||||
camera_password = conf_cameras[camera_serial]["password"]
|
||||
camera_rtsp_stream = "rtsp://{}:{}@{}:{}".format(
|
||||
camera_username,
|
||||
camera_password,
|
||||
camera["localIp"],
|
||||
camera["localRtspPort"],
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"Camera %s source stream: %s", camera["serial"], camera_rtsp_stream
|
||||
)
|
||||
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"I found a camera (%s) but it is not configured. Please configure it if you wish to see the appropriate stream. Conf cameras: %s",
|
||||
camera_serial,
|
||||
conf_cameras,
|
||||
)
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
EzvizCamera(
|
||||
hass,
|
||||
camera_username,
|
||||
camera_password,
|
||||
camera_rtsp_stream,
|
||||
camera["serial"],
|
||||
camera["name"],
|
||||
camera["deviceType"],
|
||||
camera["version"],
|
||||
camera["status"],
|
||||
camera["createTime"],
|
||||
camera["category"],
|
||||
camera["subCategory"],
|
||||
camera["customType"],
|
||||
camera["localIp"],
|
||||
camera["netIp"],
|
||||
camera["localRtspPort"],
|
||||
camera["wanIp"],
|
||||
camera["netType"],
|
||||
)
|
||||
]
|
||||
)
|
||||
except PyEzvizError as exp:
|
||||
_LOGGER.error(exp)
|
||||
return
|
||||
|
||||
|
||||
class EzvizCamera(Camera):
|
||||
"""An implementation of a Foscam IP camera."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass,
|
||||
username,
|
||||
password,
|
||||
rtsp_stream,
|
||||
serial,
|
||||
name,
|
||||
device_type,
|
||||
version,
|
||||
status,
|
||||
create_time,
|
||||
category,
|
||||
sub_category,
|
||||
custom_type,
|
||||
local_ip,
|
||||
net_ip,
|
||||
local_rtsp_port,
|
||||
wan_ip,
|
||||
net_type,
|
||||
):
|
||||
"""Initialize an Ezviz camera."""
|
||||
super().__init__()
|
||||
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._rtsp_stream = rtsp_stream
|
||||
|
||||
self._serial = serial
|
||||
self._name = name
|
||||
self._type = device_type
|
||||
self._version = version
|
||||
self._status = status
|
||||
self._create_time = create_time
|
||||
self._category = category
|
||||
self._sub_category = sub_category
|
||||
self._custom_type = custom_type
|
||||
self._local_ip = local_ip
|
||||
self._net_ip = net_ip
|
||||
self._local_rtsp_port = local_rtsp_port
|
||||
self._wan_ip = wan_ip
|
||||
self._net_type = net_type
|
||||
|
||||
self._ffmpeg = hass.data[DATA_FFMPEG]
|
||||
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
"""Return True if entity has to be polled for state.
|
||||
|
||||
False if entity pushes its state to HA.
|
||||
"""
|
||||
return True
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the Netatmo-specific camera state attributes."""
|
||||
_LOGGER.debug("Getting new attributes from ezviz camera '%s'", self._name)
|
||||
|
||||
attr = {}
|
||||
|
||||
attr["serial"] = self._serial
|
||||
attr["type"] = self._type
|
||||
attr["version"] = self._version
|
||||
# attr['status'] = self._status
|
||||
attr["createTime"] = self._create_time
|
||||
attr["category"] = self._category
|
||||
attr["subCategory"] = self._sub_category
|
||||
attr["customType"] = self._custom_type
|
||||
attr["localIp"] = self._local_ip
|
||||
attr["netIp"] = self._net_ip
|
||||
attr["localRtspPort"] = self._local_rtsp_port
|
||||
attr["wanIp"] = self._wan_ip
|
||||
attr["netType"] = self._net_type
|
||||
attr["rtspStream"] = self._rtsp_stream
|
||||
|
||||
_LOGGER.debug("Attributes of '%s' = %s", self._name, attr)
|
||||
|
||||
return attr
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return True if entity is available."""
|
||||
return self._status
|
||||
|
||||
@property
|
||||
def brand(self):
|
||||
"""Return the camera brand."""
|
||||
return "Ezviz"
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return supported features."""
|
||||
if self._rtsp_stream:
|
||||
return SUPPORT_STREAM
|
||||
return 0
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
"""Return the camera model."""
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if on."""
|
||||
return self._status
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of this camera."""
|
||||
return self._name
|
||||
|
||||
async def async_camera_image(self):
|
||||
"""Return a frame from the camera stream."""
|
||||
ffmpeg = ImageFrame(self._ffmpeg.binary, loop=self.hass.loop)
|
||||
|
||||
image = await asyncio.shield(
|
||||
ffmpeg.get_image(self._rtsp_stream, output_format=IMAGE_JPEG,)
|
||||
)
|
||||
return image
|
||||
|
||||
async def stream_source(self):
|
||||
"""Return the stream source."""
|
||||
if self._local_rtsp_port:
|
||||
rtsp_stream_source = "rtsp://{}:{}@{}:{}".format(
|
||||
self._username, self._password, self._local_ip, self._local_rtsp_port
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"Camera %s source stream: %s", self._serial, rtsp_stream_source
|
||||
)
|
||||
self._rtsp_stream = rtsp_stream_source
|
||||
return rtsp_stream_source
|
||||
return None
|
Reference in New Issue
Block a user