diff --git a/custom_components/eufy_security/alarm_control_panel.py b/custom_components/eufy_security/alarm_control_panel.py index 1f42d59..1fae8e5 100644 --- a/custom_components/eufy_security/alarm_control_panel.py +++ b/custom_components/eufy_security/alarm_control_panel.py @@ -175,8 +175,8 @@ def state(self): return CurrentModeToStateValue.TRIGGERED.value current_mode = get_child_value(self.product.properties, self.metadata.name, False) - if current_mode is False: - _LOGGER.debug(f"{self.product.name} current mode is missing, fallback to guardmode {self.guard_mode}") + #if current_mode is False: + #_LOGGER.debug(f"{self.product.name} current mode is missing, fallback to guardmode {self.guard_mode}") current_mode = get_child_value(self.product.properties, self.metadata.name, CurrentModeToState(self.guard_mode)) if current_mode in CUSTOM_CODES: @@ -190,6 +190,6 @@ def state(self): try: state = CurrentModeToStateValue[CurrentModeToState(current_mode).name].value except KeyError: - _LOGGER.debug(f"{self.product.name} current mode is missing, fallback to Unknown with guard mode {self.guard_mode}") + #_LOGGER.debug(f"{self.product.name} current mode is missing, fallback to Unknown with guard mode {self.guard_mode}") state = CurrentModeToStateValue.NONE.value return state diff --git a/custom_components/eufy_security/camera.py b/custom_components/eufy_security/camera.py index 1336448..479565b 100644 --- a/custom_components/eufy_security/camera.py +++ b/custom_components/eufy_security/camera.py @@ -81,11 +81,8 @@ def __init__(self, coordinator: EufySecurityDataUpdateCoordinator, metadata: Met # ffmpeg entities self.ffmpeg = self.coordinator.hass.data[DATA_FFMPEG] - self.product.set_ffmpeg(CameraMjpeg(self.ffmpeg.binary), ImageFrame(self.ffmpeg.binary)) async def stream_source(self) -> str: - #for line in traceback.format_stack(): - # _LOGGER.debug(f"stream_source - {line.strip()}") if self.is_streaming is False: return None return self.product.stream_url diff --git a/custom_components/eufy_security/const.py b/custom_components/eufy_security/const.py index 2465b7e..207eade 100644 --- a/custom_components/eufy_security/const.py +++ b/custom_components/eufy_security/const.py @@ -74,11 +74,13 @@ class PropertyToEntityDescription(Enum): snoozeStartTime = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) snooze = EntityDescription(id=auto(), icon="mdi:alarm-snooze") snoozeTime = EntityDescription(id=auto(), icon="mdi:alarm-snooze") + doorSensor1BatteryLevel = EntityDescription(id=auto(), state_class=SensorStateClass.MEASUREMENT, category=EntityCategory.DIAGNOSTIC) + doorSensor2BatteryLevel = EntityDescription(id=auto(), state_class=SensorStateClass.MEASUREMENT, category=EntityCategory.DIAGNOSTIC) + stream_provider = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) stream_url = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) stream_status = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) - codec = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) video_queue_size = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) # device binary sensor @@ -112,6 +114,9 @@ class PropertyToEntityDescription(Enum): snoozeHomebase = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) snoozeMotion = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) snoozeChime = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) + doorSensor1LowBattery = EntityDescription(id=auto(), device_class=BinarySensorDeviceClass.BATTERY, category=EntityCategory.DIAGNOSTIC) + doorSensor2LowBattery = EntityDescription(id=auto(), device_class=BinarySensorDeviceClass.BATTERY, category=EntityCategory.DIAGNOSTIC) + connected = EntityDescription(id=auto(), category=EntityCategory.DIAGNOSTIC) # device switch enabled = EntityDescription(id=auto()) @@ -135,6 +140,8 @@ class PropertyToEntityDescription(Enum): motionDetectionTypeHuman = EntityDescription(id=auto(), category=EntityCategory.CONFIG) motionDetectionTypeHumanRecognition = EntityDescription(id=auto(), category=EntityCategory.CONFIG) motionDetectionTypeAllOtherMotions = EntityDescription(id=auto(), category=EntityCategory.CONFIG) + door1Open = EntityDescription(id=auto()) + door2Open = EntityDescription(id=auto()) # device select powerSource = EntityDescription(id=auto(), icon="mdi:power-plug", category=EntityCategory.DIAGNOSTIC) @@ -153,8 +160,8 @@ class PropertyToEntityDescription(Enum): lightSettingsScheduleDynamicLighting = EntityDescription(id=auto(), category=EntityCategory.CONFIG) # station sensor - currentMode = EntityDescription(id=auto(), icon="mdi:security", category=EntityCategory.DIAGNOSTIC) - guardMode = EntityDescription(id=auto(), icon="mdi:security", category=EntityCategory.DIAGNOSTIC) + currentMode = EntityDescription(id=auto(), icon="mdi:security") + guardMode = EntityDescription(id=auto(), icon="mdi:security") # station select promptVolume = EntityDescription(id=auto(), icon="mdi:volume-medium", category=EntityCategory.CONFIG) diff --git a/custom_components/eufy_security/eufy_security_api/api_client.py b/custom_components/eufy_security/eufy_security_api/api_client.py index 1786400..7821aa3 100644 --- a/custom_components/eufy_security/eufy_security_api/api_client.py +++ b/custom_components/eufy_security/eufy_security_api/api_client.py @@ -122,6 +122,8 @@ async def _get_products(self, product_type: ProductType, products: list) -> dict else: product = Device(self, serial_no, properties, metadata, commands) else: + properties[MessageField.CONNECTED.value] = await self._get_is_connected(product_type, serial_no) + metadata[MessageField.CONNECTED.value] = {'key': MessageField.CONNECTED.value,'name': MessageField.CONNECTED.value,'label': 'Connected','readable': True,'writeable': False,'type': 'boolean'} product = Station(self, serial_no, properties, metadata, commands) response[serial_no] = product @@ -213,6 +215,10 @@ async def _get_is_rtsp_streaming(self, product_type: ProductType, serial_no: str result = await self._send_message_get_response(OutgoingMessage(OutgoingMessageType.is_rtsp_livestreaming, serial_no=serial_no)) return result[MessageField.LIVE_STREAMING.value] + async def _get_is_connected(self, product_type: ProductType, serial_no: str) -> bool: + result = await self._send_message_get_response(OutgoingMessage(OutgoingMessageType.is_connected, serial_no=serial_no)) + return result[MessageField.CONNECTED.value] + async def start_livestream(self, product_type: ProductType, serial_no: str) -> None: """Process start p2p livestream call""" await self._send_message_get_response(OutgoingMessage(OutgoingMessageType.start_livestream, serial_no=serial_no)) @@ -256,7 +262,7 @@ async def reboot(self, product_type: ProductType, serial_no: str) -> None: await self._send_message_get_response(OutgoingMessage(OutgoingMessageType.reboot, serial_no=serial_no)) async def _on_message(self, message: dict) -> None: - message_str = str(message)[0:5000] + message_str = str(message)[0:15000] if "livestream video data" not in message_str and "livestream audio data" not in message_str: _LOGGER.debug(f"_on_message - {message_str}") else: diff --git a/custom_components/eufy_security/eufy_security_api/camera.py b/custom_components/eufy_security/eufy_security_api/camera.py index 85aa4cc..5ed2121 100644 --- a/custom_components/eufy_security/eufy_security_api/camera.py +++ b/custom_components/eufy_security/eufy_security_api/camera.py @@ -7,7 +7,7 @@ import datetime import traceback -from .const import MessageField, STREAM_TIMEOUT_SECONDS, STREAM_SLEEP_SECONDS +from .const import MessageField, STREAM_TIMEOUT_SECONDS, STREAM_SLEEP_SECONDS, GO2RTC_RTSP_PORT from .event import Event from .exceptions import CameraRTSPStreamNotEnabled, CameraRTSPStreamNotSupported from .p2p_streamer import P2PStreamer @@ -51,13 +51,10 @@ def __init__(self, api, serial_no: str, properties: dict, metadata: dict, comman self.stream_status: StreamStatus = StreamStatus.IDLE self.stream_provider: StreamProvider = None self.stream_url: str = None - self.codec: str = None self.video_queue = asyncio.Queue() self.config = config self.voices = voices - self.ffmpeg = None - self.imagempeg = None self.image_last_updated = None self.p2p_streamer = P2PStreamer(self) @@ -77,11 +74,6 @@ def is_streaming(self) -> bool: """Is Camera in Streaming Status""" return self.stream_status == StreamStatus.STREAMING - def set_ffmpeg(self, ffmpeg, imagempeg): - """set ffmpeg binary""" - self.ffmpeg = ffmpeg - self.imagempeg = imagempeg - async def _handle_livestream_started(self, event: Event): # automatically find this function for respective event _LOGGER.debug(f"_handle_livestream_started - {event}") @@ -105,38 +97,8 @@ async def _handle_rtsp_livestream_stopped(self, event: Event): async def _handle_livestream_video_data_received(self, event: Event): # automatically find this function for respective event - if self.codec is None: - self.codec = event.data["metadata"]["videoCodec"].lower() - await self.video_queue.put(event.data["buffer"]["data"]) - async def _start_p2p_streamer(self): - self.stream_debug = "info - wait for codec value" - await wait_for_value(self.__dict__, "codec", None) - await self.p2p_streamer.start() - - async def _is_stream_url_ready(self) -> bool: - _LOGGER.debug("_is_stream_url_ready - 1") - with contextlib.suppress(Exception): - while True: - if await self.imagempeg.get_image(self.stream_url, timeout=1) is not None: - return True - return False - - async def _check_stream_url(self) -> bool: - try: - self.stream_debug = "info - check if stream url is a valid stream" - _LOGGER.debug(f"_check_stream_url - {self.stream_debug}") - await asyncio.wait_for(self._is_stream_url_ready(), STREAM_TIMEOUT_SECONDS) - self.stream_status = StreamStatus.STREAMING - self.stream_debug = "info - streaming" - _LOGGER.debug(f"_check_stream_url - {self.stream_debug}") - return True - except asyncio.TimeoutError: - self.stream_debug = "error - rtsp url was not a valid stream" - _LOGGER.debug(f"_check_stream_url - {self.stream_debug}") - return False - async def _initiate_start_stream(self, stream_type) -> bool: self.set_stream_prodiver(stream_type) self.stream_status = StreamStatus.PREPARING @@ -169,11 +131,9 @@ async def start_livestream(self) -> bool: if await self._initiate_start_stream(StreamProvider.P2P) is False: return False - self.stream_debug = "info - start ffmpeg" - _LOGGER.debug(f"start_livestream - {self.stream_debug}") - await self._start_p2p_streamer() - - return await self._check_stream_url() + await self.p2p_streamer.start() + self.stream_status = StreamStatus.STREAMING + return True async def check_and_stop_livestream(self): if self.stream_status != StreamStatus.IDLE: @@ -188,7 +148,9 @@ async def start_rtsp_livestream(self) -> bool: if await self._initiate_start_stream(StreamProvider.RTSP) is False: return False - return await self._check_stream_url() + self.stream_status = StreamStatus.STREAMING + return True + async def stop_rtsp_livestream(self): """Process stop rtsp livestream call""" @@ -267,7 +229,7 @@ def set_stream_prodiver(self, stream_provider: StreamProvider) -> None: elif self.stream_provider == StreamProvider.P2P: url = url.replace("{serial_no}", str(self.serial_no)) url = url.replace("{server_address}", str(self.config.rtsp_server_address)) - url = url.replace("{server_port}", str(self.config.rtsp_server_port)) + url = url.replace("{server_port}", str(GO2RTC_RTSP_PORT)) self.stream_url = url _LOGGER.debug(f"url - {self.stream_provider} - {self.stream_url}") diff --git a/custom_components/eufy_security/eufy_security_api/const.py b/custom_components/eufy_security/eufy_security_api/const.py index b7f74bc..d36d75b 100644 --- a/custom_components/eufy_security/eufy_security_api/const.py +++ b/custom_components/eufy_security/eufy_security_api/const.py @@ -12,6 +12,8 @@ STREAM_TIMEOUT_SECONDS = 15 STREAM_SLEEP_SECONDS = 0.25 +GO2RTC_RTSP_PORT = 8554 +GO2RTC_API_PORT = 1984 class MessageField(Enum): @@ -103,6 +105,9 @@ class EventNameToHandler(Enum): livestream_video_data_received = "livestream video data" livestream_audio_data_received = "livestream audio data" pin_verified = "pin verified" + connected = "connected" + disconnected = "disconnected" + connection_error = "connection error" class ProductType(Enum): diff --git a/custom_components/eufy_security/eufy_security_api/outgoing_message.py b/custom_components/eufy_security/eufy_security_api/outgoing_message.py index 74112cd..6c72b3e 100644 --- a/custom_components/eufy_security/eufy_security_api/outgoing_message.py +++ b/custom_components/eufy_security/eufy_security_api/outgoing_message.py @@ -88,6 +88,7 @@ class OutgoingMessageType(Enum): # station level commands chime = {MessageField.DUMMY: auto(), MessageField.DOMAIN: EventSourceType.station, MessageField.RINGTONE: None} reboot = {MessageField.DUMMY: auto(), MessageField.DOMAIN: EventSourceType.station} + is_connected = {MessageField.DUMMY: auto(), MessageField.DOMAIN: EventSourceType.station} class OutgoingMessage: diff --git a/custom_components/eufy_security/eufy_security_api/p2p_streamer.py b/custom_components/eufy_security/eufy_security_api/p2p_streamer.py index e07f04e..8716b02 100644 --- a/custom_components/eufy_security/eufy_security_api/p2p_streamer.py +++ b/custom_components/eufy_security/eufy_security_api/p2p_streamer.py @@ -7,134 +7,57 @@ import json from time import sleep import traceback +import aiohttp import os -from .const import STREAM_TIMEOUT_SECONDS, STREAM_SLEEP_SECONDS +from .const import GO2RTC_API_PORT _LOGGER: logging.Logger = logging.getLogger(__package__) -FFMPEG_COMMAND = [ - "-timeout", "1000", - "-analyzeduration", "{duration}", - "-f", "{video_codec}", - "-i", - "tcp://localhost:{port}?listen=1", - "-vcodec", "copy" -] -FFMPEG_OPTIONS = ( - " -hls_init_time 0" - " -hls_time 1" - " -hls_segment_type mpegts" - " -hls_playlist_type event " - " -hls_list_size 0" - " -preset ultrafast" - " -tune zerolatency" - " -g 15" - " -sc_threshold 0" - " -fflags genpts+nobuffer+flush_packets" - " -loglevel debug" -) - - class P2PStreamer: """Class to manage external stream provider and byte based ffmpeg streaming""" def __init__(self, camera) -> None: self.camera = camera - self.port = None - - def get_command(self): - command = FFMPEG_COMMAND.copy() - video_codec = "hevc" if self.camera.codec == "h265" else self.camera.codec - - command[command.index("-analyzeduration") + 1] = command[command.index("-analyzeduration") + 1].replace("{duration}", str(self.camera.config.ffmpeg_analyze_duration)) - command[command.index("-f") + 1] = command[command.index("-f") + 1].replace("{video_codec}", video_codec) - command[command.index("-i") + 1] = command[command.index("-i") + 1].replace("{port}", str(self.port)) - return command - - def get_options(self): - options = FFMPEG_OPTIONS - if self.camera.config.generate_ffmpeg_logs is True: - options = FFMPEG_OPTIONS + " -report" - return options - def get_output(self): - return f"-f rtsp -rtsp_transport tcp {self.camera.stream_url}" - - async def set_port(self) -> int: - """find a free port""" - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - sock.bind(("localhost", 0)) - self.port = sock.getsockname()[1] - - await asyncio.sleep(STREAM_SLEEP_SECONDS) - - async def start_ffmpeg(self) -> bool: - if await self.camera.ffmpeg.open(cmd=self.get_command(), input_source=None, extra_cmd=self.get_options(), output=self.get_output(), stderr_pipe=True, stdout_pipe=True) is False: - return False - - await asyncio.sleep(STREAM_SLEEP_SECONDS) - return True + async def chunk_generator(self): + while True: + try: + item = await asyncio.wait_for(self.camera.video_queue.get(), timeout=2.5) + _LOGGER.debug(f"chunk_generator yield data - {len(item)}") + yield bytearray(item) + except TimeoutError as te: + _LOGGER.debug(f"chunk_generator timeout Exception %s - traceback: %s", te, traceback.format_exc()) + break async def write_bytes(self): - writer = None + url = f"http://{self.camera.config.rtsp_server_address}:{GO2RTC_API_PORT}/api/stream?dst={str(self.camera.serial_no)}" + headers = {'Content-Type': 'application/octet-stream'} + try: - _, writer = await asyncio.open_connection("localhost", self.port) - asyncio.get_event_loop().create_task(self.check_live_stream(writer)) - while self.ffmpeg_available: - try: - item = await asyncio.wait_for(self.camera.video_queue.get(), timeout=2.5) - writer.write(bytearray(item)) - await writer.drain() - except TimeoutError as te: - _LOGGER.debug(f"Timeout Exception %s - traceback: %s", te, traceback.format_exc()) - break - except Exception as ex: # pylint: disable=broad-except - _LOGGER.debug(f"General Exception %s - traceback: %s", ex, traceback.format_exc()) - finally: - if writer is not None: - writer.close() + async with aiohttp.ClientSession() as session: + resp = await session.post(url, data = self.chunk_generator(), headers=headers, timeout=aiohttp.ClientTimeout(total=None, connect=5)) + _LOGGER.debug(f"write_bytes - post response - {resp.status} - {await resp.text()}") - _LOGGER.debug("p2p 7") + except Exception as ex: # pylint: disable=broad-except + _LOGGER.debug(f"write_bytes exception %s - traceback: %s", ex, traceback.format_exc()) - await self.stop() + _LOGGER.debug("write_bytes - ended") - async def check_live_stream(self, writer): - return - errored = 0 - while errored < 3: - result = await self.camera.imagempeg.get_image(self.camera.stream_url) - if result is None: - _LOGGER.debug(f"check_live_stream - result is None - {result} - {errored}") - errored = errored + 1 - else: - if len(result) == 0: - _LOGGER.debug(f"check_live_stream - result is empty - {result} - {errored}") - errored = errored + 1 - else: - _LOGGER.debug(f"check_live_stream - no error - {len(result)} - {errored}") - errored = 0 - _LOGGER.debug(f"check_live_stream - error and close {errored}") - writer.close() + # await self.stop() + async def create_stream_on_go2rtc(self): + parameters = {"name": str(self.camera.serial_no), "src": str(self.camera.serial_no)} + url = f"http://{self.camera.config.rtsp_server_address}:{GO2RTC_API_PORT}/api/streams" + async with aiohttp.ClientSession() as session: + async with session.put(url, params=parameters) as response: + result = response.status, await response.text() + _LOGGER.debug(f"create_stream_on_go2rtc - put stream response {result}") async def start(self): - """start ffmpeg process""" - await self.set_port() - - if await self.start_ffmpeg() is False: - return False - + """start streaming thread""" + # send API command to go2rtc to create a new stream + await self.create_stream_on_go2rtc() asyncio.get_event_loop().create_task(self.write_bytes()) - async def stop(self): - if self.camera.ffmpeg is not None: - try: - await self.camera.ffmpeg.close(timeout=1) - except: - pass + async def stop(self): await self.camera.check_and_stop_livestream() - - @property - def ffmpeg_available(self) -> bool: - """True if ffmpeg exists and running""" - return self.camera.ffmpeg is not None and self.camera.ffmpeg.is_running is True \ No newline at end of file diff --git a/custom_components/eufy_security/eufy_security_api/product.py b/custom_components/eufy_security/eufy_security_api/product.py index f37d1c8..2b81354 100644 --- a/custom_components/eufy_security/eufy_security_api/product.py +++ b/custom_components/eufy_security/eufy_security_api/product.py @@ -27,6 +27,7 @@ def __init__(self, api, product_type: ProductType, serial_no: str, properties: d self.metadata: dict = None self.metadata_org = metadata self.commands = commands + self.connected = True self.state_update_listener: Callable = None @@ -95,6 +96,7 @@ async def process_event(self, event: Event): handler_func = getattr(self, f"_handle_{handler.name}", None) except ValueError: # event is not acted on, skip it + _LOGGER.debug(f"event not handled -{self.serial_no} - {event}") return if handler_func is not None: @@ -110,6 +112,15 @@ async def _handle_property_changed(self, event: Event): async def _handle_pin_verified(self, event: Event): self.pin_verified_future.set_result(event) + async def _handle_connected(self, event: Event): + self.properties[MessageField.CONNECTED.value] = True + + async def _handle_disconnected(self, event: Event): + self.properties[MessageField.CONNECTED.value] = False + + async def _handle_connection_error(self, event: Event): + self.properties[MessageField.CONNECTED.value] = False + @property def is_camera(self): """checks if Product is camera""" diff --git a/custom_components/eufy_security/model.py b/custom_components/eufy_security/model.py index f88bb1b..e1cd510 100644 --- a/custom_components/eufy_security/model.py +++ b/custom_components/eufy_security/model.py @@ -24,9 +24,6 @@ class ConfigField(Enum): port = 3000 sync_interval = 600 # seconds rtsp_server_address = auto() - rtsp_server_port = 8554 - ffmpeg_analyze_duration = 1.2 # microseconds - generate_ffmpeg_logs = auto() no_stream_in_hass = False name_for_custom1 = "Custom 1" name_for_custom2 = "Custom 2" @@ -47,9 +44,6 @@ class Config: port: int = ConfigField.port.value sync_interval: int = ConfigField.sync_interval.value rtsp_server_address: str = ConfigField.host.value - rtsp_server_port: int = ConfigField.rtsp_server_port.value - ffmpeg_analyze_duration: float = ConfigField.ffmpeg_analyze_duration.value - generate_ffmpeg_logs: bool = ConfigField.generate_ffmpeg_logs.value no_stream_in_hass: bool = ConfigField.no_stream_in_hass.value name_for_custom1: str = ConfigField.name_for_custom1.value name_for_custom2: str = ConfigField.name_for_custom2.value diff --git a/custom_components/eufy_security/sensor.py b/custom_components/eufy_security/sensor.py index 6eb5583..18f06a4 100644 --- a/custom_components/eufy_security/sensor.py +++ b/custom_components/eufy_security/sensor.py @@ -22,7 +22,6 @@ class CameraSensor(Enum): stream_provider = "Stream Provider" stream_url = "Stream URL" stream_status = "Stream Status" - codec = "Video Codec" video_queue_size = "Video Queue Size" diff --git a/custom_components/eufy_security/translations/de.json b/custom_components/eufy_security/translations/de.json index 37a4ba4..f672a33 100644 --- a/custom_components/eufy_security/translations/de.json +++ b/custom_components/eufy_security/translations/de.json @@ -31,10 +31,7 @@ "title": "Eufy Security: Einrichtung", "data": { "sync_interval": "Cloud-Scan-Intervall in Sekunden [1 bis 9999]", - "rtsp_server_address": "Host-IP-Adresse für RTSP-Erweiterung (P2P)", - "rtsp_server_port": "TCP-Port für RTSP-Erweiterung (P2P)", - "ffmpeg_analyze_duration": "Dauer der Videoanalyse in Sekunden [1 bis 5] (P2P)", - "generate_ffmpeg_logs": "Generieren Sie FFMPEG-Protokolle", + "rtsp_server_address": "Host-IP-Adresse für GO2RTC-Erweiterung (P2P)", "no_stream_in_hass": "Do not use STREAM module inside Home Assistant (if you do not watch the video inside Home Assistant native streaming or you are using WebRTC, enable this to decrease CPU usage", "name_for_custom1": "Überschreibungsname für benutzerdefinierten Schutzmodus (1)", "name_for_custom2": "Überschreibungsname für benutzerdefinierten Schutzmodus (2)", diff --git a/custom_components/eufy_security/translations/en.json b/custom_components/eufy_security/translations/en.json index 8d35aaa..bea3047 100644 --- a/custom_components/eufy_security/translations/en.json +++ b/custom_components/eufy_security/translations/en.json @@ -31,10 +31,7 @@ "title": "Eufy Security: Configuration", "data": { "sync_interval": "Cloud Scan Interval in seconds [1 to 9999]", - "rtsp_server_address": "Host IP Address for RTSP Add On (P2P)", - "rtsp_server_port": "TCP Port for RTSP Add On (P2P)", - "ffmpeg_analyze_duration": "Video Analzyze Duration in seconds [1 to 5] (P2P)", - "generate_ffmpeg_logs": "Generate FFMPEG logs", + "rtsp_server_address": "Host IP Address for GO2RTC Add On (P2P)", "no_stream_in_hass": "Do not use STREAM module inside Home Assistant (if you do not watch the video inside Home Assistant native streaming or you are using WebRTC, enable this to decrease CPU usage", "name_for_custom1": "Override Name for Custom1 Guard Mode", "name_for_custom2": "Override Name for Custom2 Guard Mode", diff --git a/custom_components/eufy_security/translations/fr.json b/custom_components/eufy_security/translations/fr.json index cf20bf4..d939404 100644 --- a/custom_components/eufy_security/translations/fr.json +++ b/custom_components/eufy_security/translations/fr.json @@ -31,10 +31,7 @@ "title": "Eufy Security: Configuration", "data": { "sync_interval": "Cloud Scan Intervalle en secondes [1 à 9999]", - "rtsp_server_address": "Adresse IP de l'hôte pour le module complémentaire RTSP (P2P)", - "rtsp_server_port": "Port TCP pour module complémentaire RTSP (P2P)", - "ffmpeg_analyze_duration": "Durée de l'analyse vidéo en secondes [1 à 5] (P2P)", - "generate_ffmpeg_logs": "Générer des journaux FFMPEG", + "rtsp_server_address": "Adresse IP de l'hôte pour le module complémentaire GO2RTC (P2P)", "no_stream_in_hass": "Do not use STREAM module inside Home Assistant (if you do not watch the video inside Home Assistant native streaming or you are using WebRTC, enable this to decrease CPU usage", "name_for_custom1": "Remplacer le nom pour le mode de garde Personnalisé1", "name_for_custom2": "Remplacer le nom pour le mode de garde Personnalisé2", diff --git a/custom_components/eufy_security/translations/it.json b/custom_components/eufy_security/translations/it.json index c60c32d..7e8c6e8 100644 --- a/custom_components/eufy_security/translations/it.json +++ b/custom_components/eufy_security/translations/it.json @@ -31,10 +31,7 @@ "title": "Eufy Security: Configurazione", "data": { "sync_interval": "Intervallo scansione cloud in secondi [da 1 a 9999]", - "rtsp_server_address": "Indirizzo IP host per aggiunta RTSP (P2P)", - "rtsp_server_port": "Porta TCP per aggiunta RTSP (P2P)", - "ffmpeg_analyze_duration": "Durata analisi video in secondi [da 1 a 5] (P2P)", - "generate_ffmpeg_logs": "Genera log FFMPEG", + "rtsp_server_address": "Indirizzo IP host per aggiunta GO2RTC (P2P)", "no_stream_in_hass": "Do not use STREAM module inside Home Assistant (if you do not watch the video inside Home Assistant native streaming or you are using WebRTC, enable this to decrease CPU usage", "name_for_custom1": "Sostituisci il nome per la modalità di protezione Personalizzata1", "name_for_custom2": "Sostituisci il nome per la modalità di protezione Personalizzata2", diff --git a/custom_components/eufy_security/translations/nl.json b/custom_components/eufy_security/translations/nl.json index ebc483e..01d0984 100644 --- a/custom_components/eufy_security/translations/nl.json +++ b/custom_components/eufy_security/translations/nl.json @@ -31,10 +31,7 @@ "title": "Eufy Security: Configuratie", "data": { "sync_interval": "Cloudscan-interval in seconden [1 tot 9999]", - "rtsp_server_address": "Host IP-adres voor RTSP-add-on (P2P)", - "rtsp_server_port": "TCP Poort voor de RTSP-extensie (P2P)", - "ffmpeg_analyze_duration": "Video-analyseduur in seconden [1 tot 5] (P2P)", - "generate_ffmpeg_logs": "Genereer FFMPEG logboeken", + "rtsp_server_address": "Host IP-adres voor GO2RTC-add-on (P2P)", "no_stream_in_hass": "Gebruik geen STREAM module binnen Home Assistant (als je de video niet met Home Assistant native streaming bekijkt of je gebruikt WebRTC, zet dit aan om CPU gebruik te verminderen", "name_for_custom1": "Naam negeren voor Custom1 Beveiligings-modus", "name_for_custom2": "Naam negeren voor Custom2 Beveiligings-modus", diff --git a/custom_components/eufy_security/translations/pl.json b/custom_components/eufy_security/translations/pl.json index 73e511e..ca45d7d 100644 --- a/custom_components/eufy_security/translations/pl.json +++ b/custom_components/eufy_security/translations/pl.json @@ -31,10 +31,7 @@ "title": "Eufy Security: Konfiguracja", "data": { "sync_interval": "Interwał skanowania chmury w sekundach [1 to 9999]", - "rtsp_server_address": "Adres IP dla dodatku RTSP (P2P)", - "rtsp_server_port": "Port TCP dla dodatku RTSP (P2P)", - "ffmpeg_analyze_duration": "Czas trwania analizy wideo w sekundach [1 to 5] (P2P)", - "generate_ffmpeg_logs": "Wygeneruj logi FFMPEG", + "rtsp_server_address": "Adres IP dla dodatku GO2RTC (P2P)", "no_stream_in_hass": "Nie używaj modułu STREAM w Home Assistant (jeśli nie oglądasz wideo w natywnym streamingu Home Assistant lub używasz WebRTC, włącz to ustawienia, aby zmniejszyć zużycie procesora", "name_for_custom1": "Zastąp nazwę dla pierwszego niestandardowego trybu ochrony (Bypass)", "name_for_custom2": "Zastąp nazwę dla drugiego niestandardowego trybu ochrony (Night)", @@ -43,4 +40,4 @@ } } } -} \ No newline at end of file +} diff --git a/custom_components/eufy_security/translations/pt-BR.json b/custom_components/eufy_security/translations/pt-BR.json index 875691c..53cc14f 100644 --- a/custom_components/eufy_security/translations/pt-BR.json +++ b/custom_components/eufy_security/translations/pt-BR.json @@ -31,10 +31,7 @@ "title": "Eufy Security: Configuração", "data": { "sync_interval": "Intervalo de escaneamento na nuvem em segundos [1 to 9999]", - "rtsp_server_address": "Endereço IP do host para add-on RTSP(P2P)", - "rtsp_server_port": "Porta TCP para add-on RTSP (P2P)", - "ffmpeg_analyze_duration": "Duração da análise de vídeo em segundos [1 a 5] (P2P)", - "generate_ffmpeg_logs": "Gerar registros FFMPEG", + "rtsp_server_address": "Endereço IP do host para add-on GO2RTC(P2P)", "no_stream_in_hass": "Do not use STREAM module inside Home Assistant (if you do not watch the video inside Home Assistant native streaming or you are using WebRTC, enable this to decrease CPU usage", "name_for_custom1": "Nome de substituição para o modo de guarda personalizado 1", "name_for_custom2": "Nome de substituição para o modo de guarda personalizado 2",