Add camera platform to Tuya (#57865)

This commit is contained in:
Franck Nijhof 2021-10-16 23:57:30 +02:00 committed by GitHub
parent 2fa08ae6ab
commit d64f210b67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 137 additions and 1 deletions

View file

@ -1112,6 +1112,7 @@ omit =
homeassistant/components/tuya/__init__.py
homeassistant/components/tuya/base.py
homeassistant/components/tuya/binary_sensor.py
homeassistant/components/tuya/camera.py
homeassistant/components/tuya/climate.py
homeassistant/components/tuya/const.py
homeassistant/components/tuya/fan.py

View file

@ -0,0 +1,130 @@
"""Support for Tuya cameras."""
from __future__ import annotations
from tuya_iot import TuyaDevice, TuyaDeviceManager
from homeassistant.components import ffmpeg
from homeassistant.components.camera import SUPPORT_STREAM, Camera as CameraEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import HomeAssistantTuyaData
from .base import TuyaEntity
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DPCode
# All descriptions can be found here:
# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
CAMERAS: tuple[str, ...] = (
# Smart Camera (including doorbells)
# https://developer.tuya.com/en/docs/iot/categorysgbj?id=Kaiuz37tlpbnu
"sp",
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Tuya cameras dynamically through Tuya discovery."""
hass_data: HomeAssistantTuyaData = hass.data[DOMAIN][entry.entry_id]
@callback
def async_discover_device(device_ids: list[str]) -> None:
"""Discover and add a discovered Tuya camera."""
entities: list[TuyaCameraEntity] = []
for device_id in device_ids:
device = hass_data.device_manager.device_map[device_id]
if device.category in CAMERAS:
entities.append(TuyaCameraEntity(device, hass_data.device_manager))
async_add_entities(entities)
async_discover_device([*hass_data.device_manager.device_map])
entry.async_on_unload(
async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device)
)
class TuyaCameraEntity(TuyaEntity, CameraEntity):
"""Tuya Camera Entity."""
def __init__(
self,
device: TuyaDevice,
device_manager: TuyaDeviceManager,
) -> None:
"""Init Tuya Camera."""
super().__init__(device, device_manager)
CameraEntity.__init__(self)
@property
def supported_features(self) -> int:
"""Flag supported features."""
return SUPPORT_STREAM
@property
def is_recording(self) -> bool:
"""Return true if the device is recording."""
return self.device.status.get(DPCode.RECORD_SWITCH, False)
@property
def brand(self) -> str | None:
"""Return the camera brand."""
return "Tuya"
@property
def motion_detection_enabled(self) -> bool:
"""Return the camera motion detection status."""
return self.device.status.get(DPCode.MOTION_SWITCH, False)
async def stream_source(self) -> str | None:
"""Return the source of the stream."""
def _stream_source() -> str | None:
# This method can be replaced by the following snippet, once
# upstream changes have been merged.
#
# return self.device_manager.get_device_stream_allocate(
# self.device.id, stream_type="rtsp"
# )
#
# https://github.com/tuya/tuya-iot-python-sdk/pull/28
response = self.device_manager.api.post(
f"/v1.0/devices/{self.device.id}/stream/actions/allocate",
{"type": "rtsp"},
)
if response["success"]:
return response["result"]["url"]
return None
return await self.hass.async_add_executor_job(_stream_source)
async def async_camera_image(
self, width: int | None = None, height: int | None = None
) -> bytes | None:
"""Return a still image response from the camera."""
stream_source = await self.stream_source()
if not stream_source:
return None
return await ffmpeg.async_get_image(
self.hass,
stream_source,
width=width,
height=height,
)
@property
def model(self) -> str | None:
"""Return the camera model."""
return self.device.product_name
def enable_motion_detection(self) -> None:
"""Enable motion detection in the camera."""
self._send_command([{"code": DPCode.MOTION_SWITCH, "value": True}])
def disable_motion_detection(self) -> None:
"""Disable motion detection in camera."""
self._send_command([{"code": DPCode.MOTION_SWITCH, "value": False}])

View file

@ -46,8 +46,9 @@ TUYA_SUPPORTED_PRODUCT_CATEGORIES = (
"pc", # Power Strip
"pir", # PIR Detector
"qn", # Heater
"sos", # SOS Button
"sgbj", # Siren Alarm
"sos", # SOS Button
"sp", # Smart Camera
"wk", # Thermostat
"xdd", # Ceiling Light
"xxj", # Diffuser
@ -58,6 +59,7 @@ SMARTLIFE_APP = "smartlife"
PLATFORMS = [
"binary_sensor",
"camera",
"climate",
"fan",
"light",
@ -106,10 +108,12 @@ class DPCode(str, Enum):
LOCK = "lock" # Lock / Child lock
MATERIAL = "material" # Material
MODE = "mode" # Working mode / Mode
MOTION_SWITCH = "motion_switch" # Motion switch
MUFFLING = "muffling" # Muffling
PIR = "pir" # Motion sensor
POWDER_SET = "powder_set" # Powder
PUMP_RESET = "pump_reset" # Water pump reset
RECORD_SWITCH = "record_switch" # Recording switch
SHAKE = "shake" # Oscillating
SOS = "sos" # Emergency State
SOS_STATE = "sos_state" # Emergency mode

View file

@ -3,6 +3,7 @@
"name": "Tuya",
"documentation": "https://github.com/tuya/tuya-home-assistant",
"requirements": ["tuya-iot-py-sdk==0.5.0"],
"dependencies": ["ffmpeg"],
"codeowners": ["@Tuya", "@zlinoliver", "@METISU", "@frenck"],
"config_flow": true,
"iot_class": "cloud_push",