Poll Reolink motion when ONVIF not available (#92837)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
starkillerOG 2023-05-12 18:48:32 +02:00 committed by GitHub
parent 8711735ec0
commit 051d631504
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 2 deletions

View file

@ -14,10 +14,11 @@ from reolink_aio.exceptions import ReolinkError, SubscriptionError
from homeassistant.components import webhook
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant
from homeassistant.helpers import issue_registry as ir
from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.network import NoURLAvailableError, get_url
from .const import CONF_PROTOCOL, CONF_USE_HTTPS, DOMAIN
@ -26,6 +27,7 @@ from .exceptions import ReolinkSetupException, ReolinkWebhookException, UserNotA
DEFAULT_TIMEOUT = 60
FIRST_ONVIF_TIMEOUT = 15
SUBSCRIPTION_RENEW_THRESHOLD = 300
POLL_INTERVAL_NO_PUSH = 5
_LOGGER = logging.getLogger(__name__)
@ -59,6 +61,8 @@ class ReolinkHost:
self._base_url: str = ""
self._webhook_url: str = ""
self._webhook_reachable: asyncio.Event = asyncio.Event()
self._cancel_poll: CALLBACK_TYPE | None = None
self._poll_job = HassJob(self._async_poll_all_motion, cancel_on_shutdown=True)
self._lost_subscription: bool = False
@property
@ -169,6 +173,7 @@ class ReolinkHost:
"network_link": "https://my.home-assistant.io/redirect/network/",
},
)
await self._async_poll_all_motion()
else:
ir.async_delete_issue(self._hass, DOMAIN, "webhook_url")
@ -228,6 +233,9 @@ class ReolinkHost:
async def stop(self, event=None):
"""Disconnect the API."""
if self._cancel_poll is not None:
self._cancel_poll()
self._cancel_poll = None
self.unregister_webhook()
await self.disconnect()
@ -359,6 +367,43 @@ class ReolinkHost:
webhook.async_unregister(self._hass, self.webhook_id)
self.webhook_id = None
async def _async_poll_all_motion(self, *_) -> None:
"""Poll motion and AI states until the first ONVIF push is received."""
if self._webhook_reachable.is_set():
# ONVIF push is working, stop polling
self._cancel_poll = None
return
try:
await self._api.get_motion_state_all_ch()
except (
aiohttp.ClientConnectorError,
ReolinkError,
) as err:
_LOGGER.error(
"Reolink error while polling motion state for host %s:%s: %s",
self._api.host,
self._api.port,
str(err),
)
except asyncio.TimeoutError:
_LOGGER.error(
"Reolink timeout error while polling motion state for host %s:%s",
self._api.host,
self._api.port,
)
finally:
# schedule next poll
if not self._hass.is_stopping:
self._cancel_poll = async_call_later(
self._hass, POLL_INTERVAL_NO_PUSH, self._poll_job
)
# After receiving the new motion states in the upstream lib,
# update the binary sensors with async_write_ha_state
# The same dispatch as for the webhook can be used
async_dispatcher_send(self._hass, f"{self.webhook_id}_all", {})
async def handle_webhook(
self, hass: HomeAssistant, webhook_id: str, request: Request
) -> None:

View file

@ -45,7 +45,7 @@
},
"webhook_url": {
"title": "Reolink webhook URL unreachable",
"description": "Did not receive initial ONVIF state from {name}. Most likely, the Reolink camera can not reach the current (local) Home Assistant URL `{base_url}`, please configure a (local) HTTP address under \"Home Assistant URL\" in the [network settings]({network_link}) that points to Home Assistant. For example `http://192.168.1.10:8123` where `192.168.1.10` is the IP of the Home Assistant device. Also, make sure the Reolink camera can reach that URL."
"description": "Did not receive initial ONVIF state from {name}. Most likely, the Reolink camera can not reach the current (local) Home Assistant URL `{base_url}`, please configure a (local) HTTP address under \"Home Assistant URL\" in the [network settings]({network_link}) that points to Home Assistant. For example `http://192.168.1.10:8123` where `192.168.1.10` is the IP of the Home Assistant device. Also, make sure the Reolink camera can reach that URL. Using fast motion/AI state polling until the first ONVIF push is received."
},
"enable_port": {
"title": "Reolink port not enabled",