Bump reolink-aio to 0.7.14 and improve typing of Reolink (#103129)
* Improve typing * fix mypy * Further improve typing * Restore Literal typing * Bump reolink_aio to 0.7.13 * Bump reolink-aio to 0.7.14pull/103324/head
parent
c1d979dc07
commit
1df69f52e5
|
@ -10,6 +10,7 @@ from typing import Literal
|
||||||
|
|
||||||
from reolink_aio.api import RETRY_ATTEMPTS
|
from reolink_aio.api import RETRY_ATTEMPTS
|
||||||
from reolink_aio.exceptions import CredentialsInvalidError, ReolinkError
|
from reolink_aio.exceptions import CredentialsInvalidError, ReolinkError
|
||||||
|
from reolink_aio.software_version import NewSoftwareVersion
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
|
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
|
||||||
|
@ -45,7 +46,9 @@ class ReolinkData:
|
||||||
|
|
||||||
host: ReolinkHost
|
host: ReolinkHost
|
||||||
device_coordinator: DataUpdateCoordinator[None]
|
device_coordinator: DataUpdateCoordinator[None]
|
||||||
firmware_coordinator: DataUpdateCoordinator[str | Literal[False]]
|
firmware_coordinator: DataUpdateCoordinator[
|
||||||
|
str | Literal[False] | NewSoftwareVersion
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
|
@ -86,7 +89,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||||
async with asyncio.timeout(host.api.timeout * (RETRY_ATTEMPTS + 2)):
|
async with asyncio.timeout(host.api.timeout * (RETRY_ATTEMPTS + 2)):
|
||||||
await host.renew()
|
await host.renew()
|
||||||
|
|
||||||
async def async_check_firmware_update() -> str | Literal[False]:
|
async def async_check_firmware_update() -> str | Literal[
|
||||||
|
False
|
||||||
|
] | NewSoftwareVersion:
|
||||||
"""Check for firmware updates."""
|
"""Check for firmware updates."""
|
||||||
if not host.api.supported(None, "update"):
|
if not host.api.supported(None, "update"):
|
||||||
return False
|
return False
|
||||||
|
@ -153,7 +158,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def entry_update_listener(hass: HomeAssistant, config_entry: ConfigEntry):
|
async def entry_update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||||
"""Update the configuration of the host entity."""
|
"""Update the configuration of the host entity."""
|
||||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ from .entity import ReolinkChannelCoordinatorEntity
|
||||||
class ReolinkBinarySensorEntityDescriptionMixin:
|
class ReolinkBinarySensorEntityDescriptionMixin:
|
||||||
"""Mixin values for Reolink binary sensor entities."""
|
"""Mixin values for Reolink binary sensor entities."""
|
||||||
|
|
||||||
value: Callable[[Host, int | None], bool]
|
value: Callable[[Host, int], bool]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -43,7 +43,7 @@ class ReolinkBinarySensorEntityDescription(
|
||||||
|
|
||||||
icon: str = "mdi:motion-sensor"
|
icon: str = "mdi:motion-sensor"
|
||||||
icon_off: str = "mdi:motion-sensor-off"
|
icon_off: str = "mdi:motion-sensor-off"
|
||||||
supported: Callable[[Host, int | None], bool] = lambda host, ch: True
|
supported: Callable[[Host, int], bool] = lambda host, ch: True
|
||||||
|
|
||||||
|
|
||||||
BINARY_SENSORS = (
|
BINARY_SENSORS = (
|
||||||
|
@ -169,6 +169,6 @@ class ReolinkBinarySensorEntity(ReolinkChannelCoordinatorEntity, BinarySensorEnt
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _async_handle_event(self, event):
|
async def _async_handle_event(self, event: str) -> None:
|
||||||
"""Handle incoming event for motion detection."""
|
"""Handle incoming event for motion detection."""
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any, Literal
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp.web import Request
|
from aiohttp.web import Request
|
||||||
|
@ -81,7 +81,7 @@ class ReolinkHost:
|
||||||
return self._unique_id
|
return self._unique_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def api(self):
|
def api(self) -> Host:
|
||||||
"""Return the API object."""
|
"""Return the API object."""
|
||||||
return self._api
|
return self._api
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ class ReolinkHost:
|
||||||
"""Call the API of the camera device to update the internal states."""
|
"""Call the API of the camera device to update the internal states."""
|
||||||
await self._api.get_states()
|
await self._api.get_states()
|
||||||
|
|
||||||
async def disconnect(self):
|
async def disconnect(self) -> None:
|
||||||
"""Disconnect from the API, so the connection will be released."""
|
"""Disconnect from the API, so the connection will be released."""
|
||||||
try:
|
try:
|
||||||
await self._api.unsubscribe()
|
await self._api.unsubscribe()
|
||||||
|
@ -335,7 +335,7 @@ class ReolinkHost:
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _async_start_long_polling(self, initial=False):
|
async def _async_start_long_polling(self, initial=False) -> None:
|
||||||
"""Start ONVIF long polling task."""
|
"""Start ONVIF long polling task."""
|
||||||
if self._long_poll_task is None:
|
if self._long_poll_task is None:
|
||||||
try:
|
try:
|
||||||
|
@ -364,7 +364,7 @@ class ReolinkHost:
|
||||||
self._lost_subscription = False
|
self._lost_subscription = False
|
||||||
self._long_poll_task = asyncio.create_task(self._async_long_polling())
|
self._long_poll_task = asyncio.create_task(self._async_long_polling())
|
||||||
|
|
||||||
async def _async_stop_long_polling(self):
|
async def _async_stop_long_polling(self) -> None:
|
||||||
"""Stop ONVIF long polling task."""
|
"""Stop ONVIF long polling task."""
|
||||||
if self._long_poll_task is not None:
|
if self._long_poll_task is not None:
|
||||||
self._long_poll_task.cancel()
|
self._long_poll_task.cancel()
|
||||||
|
@ -372,7 +372,7 @@ class ReolinkHost:
|
||||||
|
|
||||||
await self._api.unsubscribe(sub_type=SubType.long_poll)
|
await self._api.unsubscribe(sub_type=SubType.long_poll)
|
||||||
|
|
||||||
async def stop(self, event=None):
|
async def stop(self, event=None) -> None:
|
||||||
"""Disconnect the API."""
|
"""Disconnect the API."""
|
||||||
if self._cancel_poll is not None:
|
if self._cancel_poll is not None:
|
||||||
self._cancel_poll()
|
self._cancel_poll()
|
||||||
|
@ -433,7 +433,7 @@ class ReolinkHost:
|
||||||
else:
|
else:
|
||||||
self._lost_subscription = False
|
self._lost_subscription = False
|
||||||
|
|
||||||
async def _renew(self, sub_type: SubType) -> None:
|
async def _renew(self, sub_type: Literal[SubType.push, SubType.long_poll]) -> None:
|
||||||
"""Execute the renew of the subscription."""
|
"""Execute the renew of the subscription."""
|
||||||
if not self._api.subscribed(sub_type):
|
if not self._api.subscribed(sub_type):
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
|
@ -512,8 +512,10 @@ class ReolinkHost:
|
||||||
|
|
||||||
_LOGGER.debug("Registered webhook: %s", event_id)
|
_LOGGER.debug("Registered webhook: %s", event_id)
|
||||||
|
|
||||||
def unregister_webhook(self):
|
def unregister_webhook(self) -> None:
|
||||||
"""Unregister the webhook for motion events."""
|
"""Unregister the webhook for motion events."""
|
||||||
|
if self.webhook_id is None:
|
||||||
|
return
|
||||||
_LOGGER.debug("Unregistering webhook %s", self.webhook_id)
|
_LOGGER.debug("Unregistering webhook %s", self.webhook_id)
|
||||||
webhook.async_unregister(self._hass, self.webhook_id)
|
webhook.async_unregister(self._hass, self.webhook_id)
|
||||||
self.webhook_id = None
|
self.webhook_id = None
|
||||||
|
|
|
@ -38,8 +38,8 @@ class ReolinkLightEntityDescription(
|
||||||
"""A class that describes light entities."""
|
"""A class that describes light entities."""
|
||||||
|
|
||||||
supported_fn: Callable[[Host, int], bool] = lambda api, ch: True
|
supported_fn: Callable[[Host, int], bool] = lambda api, ch: True
|
||||||
get_brightness_fn: Callable[[Host, int], int] | None = None
|
get_brightness_fn: Callable[[Host, int], int | None] | None = None
|
||||||
set_brightness_fn: Callable[[Host, int, float], Any] | None = None
|
set_brightness_fn: Callable[[Host, int, int], Any] | None = None
|
||||||
|
|
||||||
|
|
||||||
LIGHT_ENTITIES = (
|
LIGHT_ENTITIES = (
|
||||||
|
@ -127,13 +127,13 @@ class ReolinkLightEntity(ReolinkChannelCoordinatorEntity, LightEntity):
|
||||||
if self.entity_description.get_brightness_fn is None:
|
if self.entity_description.get_brightness_fn is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return round(
|
bright_pct = self.entity_description.get_brightness_fn(
|
||||||
255
|
self._host.api, self._channel
|
||||||
* (
|
|
||||||
self.entity_description.get_brightness_fn(self._host.api, self._channel)
|
|
||||||
/ 100.0
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
if bright_pct is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return round(255 * bright_pct / 100.0)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn light off."""
|
"""Turn light off."""
|
||||||
|
|
|
@ -18,5 +18,5 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/reolink",
|
"documentation": "https://www.home-assistant.io/integrations/reolink",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["reolink_aio"],
|
"loggers": ["reolink_aio"],
|
||||||
"requirements": ["reolink-aio==0.7.12"]
|
"requirements": ["reolink-aio==0.7.14"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ from .entity import ReolinkChannelCoordinatorEntity
|
||||||
class ReolinkNumberEntityDescriptionMixin:
|
class ReolinkNumberEntityDescriptionMixin:
|
||||||
"""Mixin values for Reolink number entities."""
|
"""Mixin values for Reolink number entities."""
|
||||||
|
|
||||||
value: Callable[[Host, int], float]
|
value: Callable[[Host, int], float | None]
|
||||||
method: Callable[[Host, int, float], Any]
|
method: Callable[[Host, int, float], Any]
|
||||||
|
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ class ReolinkNumberEntity(ReolinkChannelCoordinatorEntity, NumberEntity):
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> float:
|
def native_value(self) -> float | None:
|
||||||
"""State of the number entity."""
|
"""State of the number entity."""
|
||||||
return self.entity_description.value(self._host.api, self._channel)
|
return self.entity_description.value(self._host.api, self._channel)
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ class ReolinkSensorEntityDescription(
|
||||||
class ReolinkHostSensorEntityDescriptionMixin:
|
class ReolinkHostSensorEntityDescriptionMixin:
|
||||||
"""Mixin values for Reolink host sensor entities."""
|
"""Mixin values for Reolink host sensor entities."""
|
||||||
|
|
||||||
value: Callable[[Host], int]
|
value: Callable[[Host], int | None]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
|
@ -35,7 +35,8 @@ async def async_setup_entry(
|
||||||
|
|
||||||
|
|
||||||
class ReolinkUpdateEntity(
|
class ReolinkUpdateEntity(
|
||||||
ReolinkBaseCoordinatorEntity[str | Literal[False]], UpdateEntity
|
ReolinkBaseCoordinatorEntity[str | Literal[False] | NewSoftwareVersion],
|
||||||
|
UpdateEntity,
|
||||||
):
|
):
|
||||||
"""Update entity for a Netgear device."""
|
"""Update entity for a Netgear device."""
|
||||||
|
|
||||||
|
|
|
@ -2322,7 +2322,7 @@ renault-api==0.2.0
|
||||||
renson-endura-delta==1.6.0
|
renson-endura-delta==1.6.0
|
||||||
|
|
||||||
# homeassistant.components.reolink
|
# homeassistant.components.reolink
|
||||||
reolink-aio==0.7.12
|
reolink-aio==0.7.14
|
||||||
|
|
||||||
# homeassistant.components.idteck_prox
|
# homeassistant.components.idteck_prox
|
||||||
rfk101py==0.0.1
|
rfk101py==0.0.1
|
||||||
|
|
|
@ -1733,7 +1733,7 @@ renault-api==0.2.0
|
||||||
renson-endura-delta==1.6.0
|
renson-endura-delta==1.6.0
|
||||||
|
|
||||||
# homeassistant.components.reolink
|
# homeassistant.components.reolink
|
||||||
reolink-aio==0.7.12
|
reolink-aio==0.7.14
|
||||||
|
|
||||||
# homeassistant.components.rflink
|
# homeassistant.components.rflink
|
||||||
rflink==0.0.65
|
rflink==0.0.65
|
||||||
|
|
Loading…
Reference in New Issue