Remove onvif from mypy ignore list (#75162)
parent
b60f6c7cdd
commit
debd475a6d
|
@ -1,42 +1,50 @@
|
|||
"""Base classes for ONVIF entities."""
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
|
||||
from .const import DOMAIN
|
||||
from .device import ONVIFDevice
|
||||
from .models import Profile
|
||||
|
||||
|
||||
class ONVIFBaseEntity(Entity):
|
||||
"""Base class common to all ONVIF entities."""
|
||||
|
||||
def __init__(self, device: ONVIFDevice, profile: Profile = None) -> None:
|
||||
def __init__(self, device: ONVIFDevice) -> None:
|
||||
"""Initialize the ONVIF entity."""
|
||||
self.device: ONVIFDevice = device
|
||||
self.profile: Profile = profile
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return True if device is available."""
|
||||
return self.device.available
|
||||
|
||||
@property
|
||||
def mac_or_serial(self) -> str:
|
||||
"""Return MAC or serial, for unique_id generation.
|
||||
|
||||
MAC address is not always available, and given the number
|
||||
of non-conformant ONVIF devices we have historically supported,
|
||||
we can not guarantee serial number either. Due to this, we have
|
||||
adopted an either/or approach in the config entry setup, and can
|
||||
guarantee that one or the other will be populated.
|
||||
See: https://github.com/home-assistant/core/issues/35883
|
||||
"""
|
||||
return (
|
||||
self.device.info.mac
|
||||
or self.device.info.serial_number # type:ignore[return-value]
|
||||
)
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return a device description for device registry."""
|
||||
connections = None
|
||||
connections: set[tuple[str, str]] = set()
|
||||
if self.device.info.mac:
|
||||
connections = {(CONNECTION_NETWORK_MAC, self.device.info.mac)}
|
||||
return DeviceInfo(
|
||||
connections=connections,
|
||||
identifiers={
|
||||
# MAC address is not always available, and given the number
|
||||
# of non-conformant ONVIF devices we have historically supported,
|
||||
# we can not guarantee serial number either. Due to this, we have
|
||||
# adopted an either/or approach in the config entry setup, and can
|
||||
# guarantee that one or the other will be populated.
|
||||
# See: https://github.com/home-assistant/core/issues/35883
|
||||
(DOMAIN, self.device.info.mac or self.device.info.serial_number)
|
||||
},
|
||||
identifiers={(DOMAIN, self.mac_or_serial)},
|
||||
manufacturer=self.device.info.manufacturer,
|
||||
model=self.device.info.model,
|
||||
name=self.device.name,
|
||||
|
|
|
@ -48,15 +48,16 @@ async def async_setup_entry(
|
|||
|
||||
device.events.async_add_listener(async_check_entities)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class ONVIFBinarySensor(ONVIFBaseEntity, RestoreEntity, BinarySensorEntity):
|
||||
"""Representation of a binary ONVIF event."""
|
||||
|
||||
_attr_should_poll = False
|
||||
_attr_unique_id: str
|
||||
|
||||
def __init__(self, uid, device: ONVIFDevice, entry: er.RegistryEntry | None = None):
|
||||
def __init__(
|
||||
self, uid: str, device: ONVIFDevice, entry: er.RegistryEntry | None = None
|
||||
) -> None:
|
||||
"""Initialize the ONVIF binary sensor."""
|
||||
self._attr_unique_id = uid
|
||||
if entry is not None:
|
||||
|
@ -65,6 +66,7 @@ class ONVIFBinarySensor(ONVIFBaseEntity, RestoreEntity, BinarySensorEntity):
|
|||
self._attr_name = entry.name
|
||||
else:
|
||||
event = device.events.get_uid(uid)
|
||||
assert event
|
||||
self._attr_device_class = event.device_class
|
||||
self._attr_entity_category = event.entity_category
|
||||
self._attr_entity_registry_enabled_default = event.entity_enabled
|
||||
|
|
|
@ -30,9 +30,7 @@ class RebootButton(ONVIFBaseEntity, ButtonEntity):
|
|||
"""Initialize the button entity."""
|
||||
super().__init__(device)
|
||||
self._attr_name = f"{self.device.name} Reboot"
|
||||
self._attr_unique_id = (
|
||||
f"{self.device.info.mac or self.device.info.serial_number}_reboot"
|
||||
)
|
||||
self._attr_unique_id = f"{self.mac_or_serial}_reboot"
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Send out a SystemReboot command."""
|
||||
|
@ -49,7 +47,7 @@ class SetSystemDateAndTimeButton(ONVIFBaseEntity, ButtonEntity):
|
|||
"""Initialize the button entity."""
|
||||
super().__init__(device)
|
||||
self._attr_name = f"{self.device.name} Set System Date and Time"
|
||||
self._attr_unique_id = f"{self.device.info.mac or self.device.info.serial_number}_setsystemdatetime"
|
||||
self._attr_unique_id = f"{self.mac_or_serial}_setsystemdatetime"
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Send out a SetSystemDateAndTime command."""
|
||||
|
|
|
@ -13,6 +13,7 @@ from homeassistant.components.stream import (
|
|||
CONF_RTSP_TRANSPORT,
|
||||
CONF_USE_WALLCLOCK_AS_TIMESTAMPS,
|
||||
)
|
||||
from homeassistant.components.stream.const import RTSP_TRANSPORTS
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import HTTP_BASIC_AUTHENTICATION
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -46,6 +47,8 @@ from .const import (
|
|||
ZOOM_IN,
|
||||
ZOOM_OUT,
|
||||
)
|
||||
from .device import ONVIFDevice
|
||||
from .models import Profile
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -85,20 +88,19 @@ async def async_setup_entry(
|
|||
[ONVIFCameraEntity(device, profile) for profile in device.profiles]
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class ONVIFCameraEntity(ONVIFBaseEntity, Camera):
|
||||
"""Representation of an ONVIF camera."""
|
||||
|
||||
_attr_supported_features = CameraEntityFeature.STREAM
|
||||
|
||||
def __init__(self, device, profile):
|
||||
def __init__(self, device: ONVIFDevice, profile: Profile) -> None:
|
||||
"""Initialize ONVIF camera entity."""
|
||||
ONVIFBaseEntity.__init__(self, device, profile)
|
||||
ONVIFBaseEntity.__init__(self, device)
|
||||
Camera.__init__(self)
|
||||
self.profile = profile
|
||||
self.stream_options[CONF_RTSP_TRANSPORT] = device.config_entry.options.get(
|
||||
CONF_RTSP_TRANSPORT
|
||||
CONF_RTSP_TRANSPORT, next(iter(RTSP_TRANSPORTS))
|
||||
)
|
||||
self.stream_options[
|
||||
CONF_USE_WALLCLOCK_AS_TIMESTAMPS
|
||||
|
@ -118,8 +120,8 @@ class ONVIFCameraEntity(ONVIFBaseEntity, Camera):
|
|||
def unique_id(self) -> str:
|
||||
"""Return a unique ID."""
|
||||
if self.profile.index:
|
||||
return f"{self.device.info.mac or self.device.info.serial_number}_{self.profile.index}"
|
||||
return self.device.info.mac or self.device.info.serial_number
|
||||
return f"{self.mac_or_serial}_{self.profile.index}"
|
||||
return self.mac_or_serial
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
|
@ -149,6 +151,7 @@ class ONVIFCameraEntity(ONVIFBaseEntity, Camera):
|
|||
)
|
||||
|
||||
if image is None:
|
||||
assert self._stream_uri
|
||||
return await ffmpeg.async_get_image(
|
||||
self.hass,
|
||||
self._stream_uri,
|
||||
|
|
|
@ -42,21 +42,21 @@ from .models import PTZ, Capabilities, DeviceInfo, Profile, Resolution, Video
|
|||
class ONVIFDevice:
|
||||
"""Manages an ONVIF device."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry = None) -> None:
|
||||
device: ONVIFCamera
|
||||
events: EventManager
|
||||
|
||||
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||
"""Initialize the device."""
|
||||
self.hass: HomeAssistant = hass
|
||||
self.config_entry: ConfigEntry = config_entry
|
||||
self.available: bool = True
|
||||
|
||||
self.device: ONVIFCamera = None
|
||||
self.events: EventManager = None
|
||||
|
||||
self.info: DeviceInfo = DeviceInfo()
|
||||
self.capabilities: Capabilities = Capabilities()
|
||||
self.profiles: list[Profile] = []
|
||||
self.max_resolution: int = 0
|
||||
|
||||
self._dt_diff_seconds: int = 0
|
||||
self._dt_diff_seconds: float = 0
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
|
@ -99,6 +99,7 @@ class ONVIFDevice:
|
|||
await self.async_check_date_and_time()
|
||||
|
||||
# Create event manager
|
||||
assert self.config_entry.unique_id
|
||||
self.events = EventManager(
|
||||
self.hass, self.device, self.config_entry.unique_id
|
||||
)
|
||||
|
@ -297,7 +298,7 @@ class ONVIFDevice:
|
|||
"""Obtain media profiles for this device."""
|
||||
media_service = self.device.create_media_service()
|
||||
result = await media_service.GetProfiles()
|
||||
profiles = []
|
||||
profiles: list[Profile] = []
|
||||
|
||||
if not isinstance(result, list):
|
||||
return profiles
|
||||
|
@ -396,7 +397,7 @@ class ONVIFDevice:
|
|||
req.ProfileToken = profile.token
|
||||
if move_mode == CONTINUOUS_MOVE:
|
||||
# Guard against unsupported operation
|
||||
if not profile.ptz.continuous:
|
||||
if not profile.ptz or not profile.ptz.continuous:
|
||||
LOGGER.warning(
|
||||
"ContinuousMove not supported on device '%s'", self.name
|
||||
)
|
||||
|
@ -419,7 +420,7 @@ class ONVIFDevice:
|
|||
)
|
||||
elif move_mode == RELATIVE_MOVE:
|
||||
# Guard against unsupported operation
|
||||
if not profile.ptz.relative:
|
||||
if not profile.ptz or not profile.ptz.relative:
|
||||
LOGGER.warning(
|
||||
"RelativeMove not supported on device '%s'", self.name
|
||||
)
|
||||
|
@ -436,7 +437,7 @@ class ONVIFDevice:
|
|||
await ptz_service.RelativeMove(req)
|
||||
elif move_mode == ABSOLUTE_MOVE:
|
||||
# Guard against unsupported operation
|
||||
if not profile.ptz.absolute:
|
||||
if not profile.ptz or not profile.ptz.absolute:
|
||||
LOGGER.warning(
|
||||
"AbsoluteMove not supported on device '%s'", self.name
|
||||
)
|
||||
|
@ -453,6 +454,11 @@ class ONVIFDevice:
|
|||
await ptz_service.AbsoluteMove(req)
|
||||
elif move_mode == GOTOPRESET_MOVE:
|
||||
# Guard against unsupported operation
|
||||
if not profile.ptz or not profile.ptz.presets:
|
||||
LOGGER.warning(
|
||||
"Absolute Presets not supported on device '%s'", self.name
|
||||
)
|
||||
return
|
||||
if preset_val not in profile.ptz.presets:
|
||||
LOGGER.warning(
|
||||
"PTZ preset '%s' does not exist on device '%s'. Available Presets: %s",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from homeassistant.components.sensor import RestoreSensor
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -47,8 +48,6 @@ async def async_setup_entry(
|
|||
|
||||
device.events.async_add_listener(async_check_entities)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class ONVIFSensor(ONVIFBaseEntity, RestoreSensor):
|
||||
"""Representation of a ONVIF sensor event."""
|
||||
|
@ -65,6 +64,7 @@ class ONVIFSensor(ONVIFBaseEntity, RestoreSensor):
|
|||
self._attr_native_unit_of_measurement = entry.unit_of_measurement
|
||||
else:
|
||||
event = device.events.get_uid(uid)
|
||||
assert event
|
||||
self._attr_device_class = event.device_class
|
||||
self._attr_entity_category = event.entity_category
|
||||
self._attr_entity_registry_enabled_default = event.entity_enabled
|
||||
|
@ -75,7 +75,7 @@ class ONVIFSensor(ONVIFBaseEntity, RestoreSensor):
|
|||
super().__init__(device)
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType | date | datetime:
|
||||
def native_value(self) -> StateType | date | datetime | Decimal:
|
||||
"""Return the value reported by the sensor."""
|
||||
if (event := self.device.events.get_uid(self._attr_unique_id)) is not None:
|
||||
return event.value
|
||||
|
|
15
mypy.ini
15
mypy.ini
|
@ -2689,21 +2689,6 @@ ignore_errors = true
|
|||
[mypy-homeassistant.components.minecraft_server.sensor]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.onvif.base]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.onvif.binary_sensor]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.onvif.camera]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.onvif.device]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.onvif.sensor]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.sonos]
|
||||
ignore_errors = true
|
||||
|
||||
|
|
|
@ -27,11 +27,6 @@ IGNORED_MODULES: Final[list[str]] = [
|
|||
"homeassistant.components.minecraft_server",
|
||||
"homeassistant.components.minecraft_server.helpers",
|
||||
"homeassistant.components.minecraft_server.sensor",
|
||||
"homeassistant.components.onvif.base",
|
||||
"homeassistant.components.onvif.binary_sensor",
|
||||
"homeassistant.components.onvif.camera",
|
||||
"homeassistant.components.onvif.device",
|
||||
"homeassistant.components.onvif.sensor",
|
||||
"homeassistant.components.sonos",
|
||||
"homeassistant.components.sonos.alarms",
|
||||
"homeassistant.components.sonos.binary_sensor",
|
||||
|
|
Loading…
Reference in New Issue