Add support for doorbells and chimes (#1435)

Add support for `smart` chimes and `smartcam` doorbells that are not hub child devices.
Co-authored-by: Steven B <51370195+sdb9696@users.noreply.github.com>
This commit is contained in:
steveredden
2025-01-23 03:22:41 -06:00
committed by GitHub
parent acc0e9a80a
commit 54bb53899e
13 changed files with 75 additions and 42 deletions

View File

@@ -159,6 +159,7 @@ def get_device_class_from_family(
"SMART.KASAHUB": SmartDevice,
"SMART.KASASWITCH": SmartDevice,
"SMART.IPCAMERA.HTTPS": SmartCamDevice,
"SMART.TAPODOORBELL.HTTPS": SmartCamDevice,
"SMART.TAPOROBOVAC.HTTPS": SmartDevice,
"IOT.SMARTPLUGSWITCH": IotPlug,
"IOT.SMARTBULB": IotBulb,
@@ -194,7 +195,10 @@ def get_protocol(config: DeviceConfig, *, strict: bool = False) -> BaseProtocol
protocol_name = ctype.device_family.value.split(".")[0]
_LOGGER.debug("Finding protocol for %s", ctype.device_family)
if ctype.device_family is DeviceFamily.SmartIpCamera:
if ctype.device_family in {
DeviceFamily.SmartIpCamera,
DeviceFamily.SmartTapoDoorbell,
}:
if strict and ctype.encryption_type is not DeviceEncryptionType.Aes:
return None
return SmartCamProtocol(transport=SslAesTransport(config=config))

View File

@@ -22,6 +22,8 @@ class DeviceType(Enum):
Fan = "fan"
Thermostat = "thermostat"
Vacuum = "vacuum"
Chime = "chime"
Doorbell = "doorbell"
Unknown = "unknown"
@staticmethod

View File

@@ -79,6 +79,8 @@ class DeviceFamily(Enum):
SmartKasaHub = "SMART.KASAHUB"
SmartIpCamera = "SMART.IPCAMERA"
SmartTapoRobovac = "SMART.TAPOROBOVAC"
SmartTapoChime = "SMART.TAPOCHIME"
SmartTapoDoorbell = "SMART.TAPODOORBELL"
class _DeviceConfigBaseMixin(DataClassJSONMixin):

View File

@@ -885,6 +885,8 @@ class SmartDevice(Device):
return DeviceType.Thermostat
if "ROBOVAC" in device_type:
return DeviceType.Vacuum
if "TAPOCHIME" in device_type:
return DeviceType.Chime
_LOGGER.warning("Unknown device type, falling back to plug")
return DeviceType.Plug

View File

@@ -9,7 +9,6 @@ from typing import Annotated
from urllib.parse import quote_plus
from ...credentials import Credentials
from ...device_type import DeviceType
from ...feature import Feature
from ...json import loads as json_loads
from ...module import FeatureAttribute, Module
@@ -31,6 +30,8 @@ class StreamResolution(StrEnum):
class Camera(SmartCamModule):
"""Implementation of device module."""
REQUIRED_COMPONENT = "video"
def _initialize_features(self) -> None:
"""Initialize features after the initial update."""
if Module.LensMask in self._device.modules:
@@ -126,7 +127,3 @@ class Camera(SmartCamModule):
return None
return f"http://{self._device.host}:{ONVIF_PORT}/onvif/device_service"
async def _check_supported(self) -> bool:
"""Additional check to see if the module is supported by the device."""
return self._device.device_type is DeviceType.Camera

View File

@@ -85,6 +85,13 @@ class SmartCamChild(SmartChildDevice, SmartCamDevice):
# devices
self._info = self._map_child_info_from_parent(info)
@property
def device_type(self) -> DeviceType:
"""Return the device type."""
if self._device_type == DeviceType.Unknown and self._info:
self._device_type = self._get_device_type_from_sysinfo(self._info)
return self._device_type
@staticmethod
def _get_device_info(
info: dict[str, Any], discovery_info: dict[str, Any] | None

View File

@@ -26,12 +26,15 @@ class SmartCamDevice(SmartDevice):
@staticmethod
def _get_device_type_from_sysinfo(sysinfo: dict[str, Any]) -> DeviceType:
"""Find type to be displayed as a supported device category."""
if (
sysinfo
and (device_type := sysinfo.get("device_type"))
and device_type.endswith("HUB")
):
if not (device_type := sysinfo.get("device_type")):
return DeviceType.Unknown
if device_type.endswith("HUB"):
return DeviceType.Hub
if "DOORBELL" in device_type:
return DeviceType.Doorbell
return DeviceType.Camera
@staticmethod
@@ -165,11 +168,6 @@ class SmartCamDevice(SmartDevice):
if (
mod.REQUIRED_COMPONENT
and mod.REQUIRED_COMPONENT not in self._components
# Always add Camera module to cameras
and (
mod._module_name() != Module.Camera
or self._device_type is not DeviceType.Camera
)
):
continue
module = mod(self, mod._module_name())
@@ -258,7 +256,7 @@ class SmartCamDevice(SmartDevice):
@property
def device_type(self) -> DeviceType:
"""Return the device type."""
if self._device_type == DeviceType.Unknown:
if self._device_type == DeviceType.Unknown and self._info:
self._device_type = self._get_device_type_from_sysinfo(self._info)
return self._device_type