diff --git a/custom_components/rtkey/__init__.py b/custom_components/rtkey/__init__.py index 5adc304..10b74dc 100644 --- a/custom_components/rtkey/__init__.py +++ b/custom_components/rtkey/__init__.py @@ -697,7 +697,11 @@ class RTKeyCamerasApi: url = url.update_query({"token": streamer_token}) return str(url) - async def get_camera_stream_url(self, camera_id: str) -> str | None: + async def get_camera_stream_url(self, camera_id: str, retry: bool = False) -> str | None: + if self._tokens_invalid and not retry: + _LOGGER.debug(f"Токены протухшие, обновляем перед запросом стрима для {camera_id}") + await self.refresh_tokens() + info = self.camera_tokens.get(camera_id) streamer_token = info.streamer_token if info else None @@ -708,6 +712,27 @@ class RTKeyCamerasApi: }) if streamer_token: url = url.update_query({"token": streamer_token}) + + r = await self._api_get(url, _DEFAULT_HEADERS, timeout=10) + if r is None: + return str(url) + + if r.status == 403 and not retry: + camera_name = self.get_camera_name(camera_id) + _LOGGER.warning(f"Токен стрима для {camera_name} ({camera_id}) протух (403), запускаем обновление...") + self._tokens_invalid = True + await self.refresh_tokens() + return await self.get_camera_stream_url(camera_id, retry=True) + + if r.status == 403 and retry: + camera_name = self.get_camera_name(camera_id) + _LOGGER.error(f"Повторный 403 для стрима {camera_name} ({camera_id}) — проблема с авторизацией") + return None + + if r.status == 200: + return str(url) + + _LOGGER.warning(f"Стрим для {camera_id}: статус {r.status}") return str(url) # === Домофон: открытие === diff --git a/custom_components/rtkey/camera.py b/custom_components/rtkey/camera.py index 3d16e2f..252ac28 100644 --- a/custom_components/rtkey/camera.py +++ b/custom_components/rtkey/camera.py @@ -1,4 +1,3 @@ -import datetime from pathlib import Path from typing import Any @@ -8,7 +7,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity import EntityCategory -from . import _LOGGER, DOMAIN, RTKeyCamerasApi, TOKEN_REFRESH_BUFFER +from . import _LOGGER, DOMAIN, RTKeyCamerasApi async def async_setup_entry( @@ -64,37 +63,6 @@ class RTKeyCamera(Camera): self._attr_unique_id = f"camera_{self.camera_id}" self._attr_name = self.device_name - self._unsub_stream_refresh: Any = None - - async def async_added_to_hass(self) -> None: - await super().async_added_to_hass() - - self._unsub_stream_refresh = async_track_time_interval( - self.hass, - self._stream_refresh, - datetime.timedelta(seconds=TOKEN_REFRESH_BUFFER), - ) - _LOGGER.debug(f"Таймер обновления стрима запущен для {self.device_name}") - - async def async_will_remove_from_hass(self) -> None: - if self._unsub_stream_refresh: - self._unsub_stream_refresh() - self._unsub_stream_refresh = None - await super().async_will_remove_from_hass() - - async def _stream_refresh(self, now: datetime.datetime) -> None: - try: - if self.cameras_api._tokens_invalid: - _LOGGER.debug(f"Обнаружены протухшие токены, обновляем для {self.device_name}") - await self.cameras_api.refresh_tokens() - - url = await self.stream_source() - if url and self.stream and getattr(self.stream, "source", None) != url: - _LOGGER.debug(f"Обновляем URL стрима для {self.device_name}") - self.stream.update_source(url) - except Exception as e: - _LOGGER.error(f"Ошибка обновления стрима для {self.camera_id}: {e}") - async def stream_source(self) -> str | None: return await self.cameras_api.get_camera_stream_url(self.camera_id)