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