Add camera platform to Tuya (#57865)
This commit is contained in:
parent
2fa08ae6ab
commit
d64f210b67
4 changed files with 137 additions and 1 deletions
|
@ -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
|
||||
|
|
130
homeassistant/components/tuya/camera.py
Normal file
130
homeassistant/components/tuya/camera.py
Normal 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}])
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Reference in a new issue