From 724f99acf4a385dfde8b97d05faabbcc552cdcc4 Mon Sep 17 00:00:00 2001 From: domhaas Date: Thu, 1 Feb 2024 15:33:37 +0100 Subject: [PATCH 1/7] Fixed typo in german translation --- custom_components/frigate/translations/de.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/frigate/translations/de.json b/custom_components/frigate/translations/de.json index 5c8ff6e5..c554b60d 100644 --- a/custom_components/frigate/translations/de.json +++ b/custom_components/frigate/translations/de.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "URL, die Sie für den Zugriff auf Frigate verwenden (z. B. \"http://fregate:5000/\")\n\nWenn Sie HassOS mit dem Addon verwenden, sollte die URL „http://ccab4aaf-fregate:5000/“ lauten\n\nHome Assistant benötigt für alle Funktionen Zugriff auf Port 5000 (api) und 1935 (rtmp).\n\nDie Integration richtet Sensoren, Kameras und Medienbrowser-Funktionen ein.\n\nSensoren:\n- Statistiken zur Überwachung der Frigate-Leistung\n- Objektzählungen für alle Zonen und Kameras\n\nKameras:\n- Kameras für Bild des zuletzt erkannten Objekts für jede Kamera\n- Kameraeinheiten mit Stream-Unterstützung (erfordert RTMP)\n\nMedienbrowser:\n- Umfangreiche Benutzeroberfläche mit Vorschaubildern zum Durchsuchen von Event-Clips\n- Umfangreiche Benutzeroberfläche zum Durchsuchen von 24/7-Aufzeichnungen nach Monat, Tag, Kamera und Uhrzeit\n\nAPI:\n- Benachrichtigungs-API mit öffentlich zugänglichen Endpunkten für Bilder in Benachrichtigungen", + "description": "URL, die Sie für den Zugriff auf Frigate verwenden (z. B. \"http://frigate:5000/\")\n\nWenn Sie HassOS mit dem Addon verwenden, sollte die URL „http://ccab4aaf-frigate:5000/“ lauten\n\nHome Assistant benötigt für alle Funktionen Zugriff auf Port 5000 (api) und 1935 (rtmp).\n\nDie Integration richtet Sensoren, Kameras und Medienbrowser-Funktionen ein.\n\nSensoren:\n- Statistiken zur Überwachung der Frigate-Leistung\n- Objektzählungen für alle Zonen und Kameras\n\nKameras:\n- Kameras für Bild des zuletzt erkannten Objekts für jede Kamera\n- Kameraeinheiten mit Stream-Unterstützung (erfordert RTMP)\n\nMedienbrowser:\n- Umfangreiche Benutzeroberfläche mit Vorschaubildern zum Durchsuchen von Event-Clips\n- Umfangreiche Benutzeroberfläche zum Durchsuchen von 24/7-Aufzeichnungen nach Monat, Tag, Kamera und Uhrzeit\n\nAPI:\n- Benachrichtigungs-API mit öffentlich zugänglichen Endpunkten für Bilder in Benachrichtigungen", "data": { "url": "URL" } @@ -32,4 +32,4 @@ "only_advanced_options": "Der erweiterte Modus ist deaktiviert und es stehen nur erweiterte Optionen zur Verfügung" } } -} \ No newline at end of file +} From 16b7dace15dc5cfc15444d75658c618bc2ec04a4 Mon Sep 17 00:00:00 2001 From: Antoine Chatelain <46867831+Redblockmasteur@users.noreply.github.com> Date: Mon, 12 Feb 2024 15:16:55 +0100 Subject: [PATCH 2/7] Add French translation creat fr.json --- .../frigate/translations/fr.json | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 custom_components/frigate/translations/fr.json diff --git a/custom_components/frigate/translations/fr.json b/custom_components/frigate/translations/fr.json new file mode 100644 index 00000000..7765b53f --- /dev/null +++ b/custom_components/frigate/translations/fr.json @@ -0,0 +1,36 @@ +{ + "config": { + "step": { + "user": { + "description": "URL que vous utilisez pour accéder à Frigate (par exemple, `http://frigate:5000/`)\n\nSi vous utilisez HassOS avec l'addon, l'URL devrait être `http://ccab4aaf-frigate:5000/`\n\nHome Assistant a besoin d'accès au port 5000 (api) et 1935 (rtmp) pour toutes les fonctionnalités.\n\nL'intégration configurera des capteurs, des caméras et la fonctionnalité de navigateur multimédia.\n\nCapteurs :\n- Statistiques pour surveiller la performance de Frigate\n- Comptes d'objets pour toutes les zones et caméras\n\nCaméras :\n- Caméras pour l'image du dernier objet détecté pour chaque caméra\n- Entités de caméra avec support de flux (nécessite RTMP)\n\nNavigateur multimédia :\n- Interface riche avec miniatures pour parcourir les clips d'événements\n- Interface riche pour parcourir les enregistrements 24/7 par mois, jour, caméra, heure\n\nAPI :\n- API de notification avec des points de terminaison publics pour les images dans les notifications", + "data": { + "url": "URL" + } + } + }, + "error": { + "cannot_connect": "Échec de la connexion", + "invalid_url": "URL invalide" + }, + "abort": { + "already_configured": "L'appareil est déjà configuré" + } + }, + "options": { + "step": { + "init": { + "data": { + "enable_webrtc": "Activer WebRTC pour les flux de caméra", + "rtmp_url_template": "Modèle d'URL RTMP (voir la documentation)", + "rtsp_url_template": "Modèle d'URL RTSP (voir la documentation)", + "media_browser_enable": "Activer le navigateur multimédia", + "notification_proxy_enable": "Activer le proxy d'événement de notification non authentifié", + "notification_proxy_expire_after_seconds": "Interdire l'accès à la notification non authentifiée après secondes (0=jamais)" + } + } + }, + "abort": { + "only_advanced_options": "Le mode avancé est désactivé et il n'y a que des options avancées" + } + } +} \ No newline at end of file From 63b022e8717b38535dbab387d9c08eafe37c6ef7 Mon Sep 17 00:00:00 2001 From: aptalca <541623+aptalca@users.noreply.github.com> Date: Mon, 12 Feb 2024 21:16:35 -0500 Subject: [PATCH 3/7] Unpin pytz in manifest requirement Rely on the pytz version included with Home Assistant --- custom_components/frigate/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/frigate/manifest.json b/custom_components/frigate/manifest.json index 8105fdcb..347ac797 100644 --- a/custom_components/frigate/manifest.json +++ b/custom_components/frigate/manifest.json @@ -13,6 +13,6 @@ "documentation": "https://github.com/blakeblackshear/frigate", "iot_class": "local_push", "issue_tracker": "https://github.com/blakeblackshear/frigate-hass-integration/issues", - "requirements": ["pytz==2022.7"], + "requirements": ["pytz"], "version": "5.0.1" } From f54d8272cbfd24a3acbffc46f215843a070bedbc Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Wed, 6 Mar 2024 15:18:26 -0700 Subject: [PATCH 4/7] Add sound level sensor --- custom_components/frigate/icons.py | 1 + custom_components/frigate/sensor.py | 90 ++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/custom_components/frigate/icons.py b/custom_components/frigate/icons.py index 61675dee..e8a12807 100644 --- a/custom_components/frigate/icons.py +++ b/custom_components/frigate/icons.py @@ -19,6 +19,7 @@ ICON_PERSON = "mdi:human" ICON_SERVER = "mdi:server" ICON_SPEEDOMETER = "mdi:speedometer" +ICON_WAVEFORM = "mdi:waveform" ICON_DEFAULT_ON = "mdi:home" diff --git a/custom_components/frigate/sensor.py b/custom_components/frigate/sensor.py index 9bf3b963..890cf49e 100644 --- a/custom_components/frigate/sensor.py +++ b/custom_components/frigate/sensor.py @@ -5,7 +5,12 @@ from typing import Any from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_URL, PERCENTAGE, UnitOfTemperature +from homeassistant.const import ( + CONF_URL, + PERCENTAGE, + UnitOfSoundPressure, + UnitOfTemperature, +) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -24,7 +29,13 @@ get_zones, ) from .const import ATTR_CONFIG, ATTR_COORDINATOR, DOMAIN, FPS, MS, NAME -from .icons import ICON_CORAL, ICON_SERVER, ICON_SPEEDOMETER, get_icon_from_type +from .icons import ( + ICON_CORAL, + ICON_SERVER, + ICON_SPEEDOMETER, + ICON_WAVEFORM, + get_icon_from_type, +) _LOGGER: logging.Logger = logging.getLogger(__name__) @@ -75,6 +86,9 @@ async def async_setup_entry( ] ) + if frigate_config["cameras"][name]["audio"]["enabled_in_config"]: + entities.append(CameraSoundSensor(coordinator, entry, name)) + frigate_config = hass.data[DOMAIN][entry.entry_id][ATTR_CONFIG] entities.extend( [ @@ -394,6 +408,78 @@ def icon(self) -> str: return ICON_SPEEDOMETER +class CameraSoundSensor(FrigateEntity, CoordinatorEntity): # type: ignore[misc] + """Frigate Camera Sound Level class.""" + + def __init__( + self, + coordinator: FrigateDataUpdateCoordinator, + config_entry: ConfigEntry, + cam_name: str, + ) -> None: + """Construct a CameraSoundSensor.""" + FrigateEntity.__init__(self, config_entry) + CoordinatorEntity.__init__(self, coordinator) + self._cam_name = cam_name + self._attr_entity_registry_enabled_default = True + + @property + def unique_id(self) -> str: + """Return a unique ID to use for this entity.""" + return get_frigate_entity_unique_id( + self._config_entry.entry_id, + "sensor_sound_level", + f"{self._cam_name}_dB", + ) + + @property + def device_info(self) -> DeviceInfo: + """Get device information.""" + return { + "identifiers": { + get_frigate_device_identifier(self._config_entry, self._cam_name) + }, + "via_device": get_frigate_device_identifier(self._config_entry), + "name": get_friendly_name(self._cam_name), + "model": self._get_model(), + "configuration_url": f"{self._config_entry.data.get(CONF_URL)}/cameras/{self._cam_name}", + "manufacturer": NAME, + } + + @property + def name(self) -> str: + """Return the name of the sensor.""" + return "sound_level" + + @property + def unit_of_measurement(self) -> str: + """Return the unit of measurement of the sensor.""" + return UnitOfSoundPressure.DECIBEL + + @property + def state(self) -> int | None: + """Return the state of the sensor.""" + + if self.coordinator.data: + data = ( + self.coordinator.data.get("cameras", {}) + .get(self._cam_name, {}) + .get("audio_dBFS") + ) + + if data is not None: + try: + return round(float(data)) + except ValueError: + pass + return None + + @property + def icon(self) -> str: + """Return the icon of the sensor.""" + return ICON_WAVEFORM + + class FrigateObjectCountSensor(FrigateMQTTEntity): """Frigate Motion Sensor class.""" From ab89b3a8511d31654f83d50a719dad256ef94682 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Wed, 6 Mar 2024 15:24:27 -0700 Subject: [PATCH 5/7] Add tests --- custom_components/frigate/sensor.py | 2 +- tests/__init__.py | 2 ++ tests/test_sensor.py | 45 ++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/custom_components/frigate/sensor.py b/custom_components/frigate/sensor.py index 890cf49e..a276fa17 100644 --- a/custom_components/frigate/sensor.py +++ b/custom_components/frigate/sensor.py @@ -449,7 +449,7 @@ def device_info(self) -> DeviceInfo: @property def name(self) -> str: """Return the name of the sensor.""" - return "sound_level" + return "sound level" @property def unit_of_measurement(self) -> str: diff --git a/tests/__init__.py b/tests/__init__.py index b2e828ef..4d5e8645 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -62,6 +62,7 @@ TEST_SENSOR_FRONT_DOOR_FFMPEG_CPU_USAGE = "sensor.front_door_ffmpeg_cpu_usage" TEST_SENSOR_FRONT_DOOR_PROCESS_FPS_ENTITY_ID = "sensor.front_door_process_fps" TEST_SENSOR_FRONT_DOOR_SKIPPED_FPS_ENTITY_ID = "sensor.front_door_skipped_fps" +TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID = "sensor.front_door_sound_level" TEST_SENSOR_FRIGATE_STATUS_ENTITY_ID = "sensor.frigate_status" TEST_UPDATE_FRIGATE_CONTAINER_ENTITY_ID = "update.frigate_server" @@ -181,6 +182,7 @@ "ffmpeg_pid": 54, "process_fps": 4.0, "skipped_fps": 0.0, + "audio_dBFS": -12, }, }, "detection_fps": 13.7, diff --git a/tests/test_sensor.py b/tests/test_sensor.py index a3bc9ef2..b7267495 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -28,8 +28,9 @@ ICON_PERSON, ICON_SERVER, ICON_SPEEDOMETER, + ICON_WAVEFORM, ) -from homeassistant.const import PERCENTAGE, UnitOfTemperature +from homeassistant.const import PERCENTAGE, UnitOfSoundPressure, UnitOfTemperature from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er import homeassistant.util.dt as dt_util @@ -51,6 +52,7 @@ TEST_SENSOR_FRONT_DOOR_PERSON_ENTITY_ID, TEST_SENSOR_FRONT_DOOR_PROCESS_FPS_ENTITY_ID, TEST_SENSOR_FRONT_DOOR_SKIPPED_FPS_ENTITY_ID, + TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID, TEST_SENSOR_GPU_LOAD_ENTITY_ID, TEST_SENSOR_STEPS_ALL_ENTITY_ID, TEST_SENSOR_STEPS_PERSON_ENTITY_ID, @@ -414,6 +416,47 @@ async def test_camera_fps_sensor(hass: HomeAssistant) -> None: assert entity_state.state == "unknown" +async def test_camera_audio_sensor(hass: HomeAssistant) -> None: + """Test CameraAudioLevel state.""" + + client = create_mock_frigate_client() + await setup_mock_frigate_config_entry(hass, client=client) + await enable_and_load_entity(hass, client, TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID) + + entity_state = hass.states.get(TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID) + assert entity_state + assert entity_state.state == "-12" + assert entity_state.attributes["icon"] == ICON_WAVEFORM + assert entity_state.attributes["unit_of_measurement"] == UnitOfSoundPressure.DECIBEL + + stats: dict[str, Any] = copy.deepcopy(TEST_STATS) + client.async_get_stats = AsyncMock(return_value=stats) + + stats["cameras"]["front_door"]["audio_dBFS"] = -3.9 + async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) + await hass.async_block_till_done() + + entity_state = hass.states.get(TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID) + assert entity_state + assert entity_state.state == "-4" + + stats["cameras"]["front_door"]["audio_dBFS"] = None + async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) + await hass.async_block_till_done() + + entity_state = hass.states.get(TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID) + assert entity_state + assert entity_state.state == "unknown" + + stats["cameras"]["front_door"]["audio_dBFS"] = "NOT_A_NUMBER" + async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) + await hass.async_block_till_done() + + entity_state = hass.states.get(TEST_SENSOR_FRONT_DOOR_SOUND_LEVEL_ID) + assert entity_state + assert entity_state.state == "unknown" + + async def test_camera_cpu_usage_sensor(hass: HomeAssistant) -> None: """Test CameraProcessCpuSensor state.""" From b25b0957c3c094055fb2d18820cccd4c23f09fc7 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Wed, 6 Mar 2024 15:30:10 -0700 Subject: [PATCH 6/7] Fix return type --- custom_components/frigate/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/frigate/sensor.py b/custom_components/frigate/sensor.py index a276fa17..6a20e1e2 100644 --- a/custom_components/frigate/sensor.py +++ b/custom_components/frigate/sensor.py @@ -452,7 +452,7 @@ def name(self) -> str: return "sound level" @property - def unit_of_measurement(self) -> str: + def unit_of_measurement(self) -> Any: """Return the unit of measurement of the sensor.""" return UnitOfSoundPressure.DECIBEL From 8d497edd471197730060cae17f6d7d678b9e705c Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 19 Mar 2024 06:08:59 -0600 Subject: [PATCH 7/7] Update to 5.1.0 --- custom_components/frigate/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/frigate/manifest.json b/custom_components/frigate/manifest.json index 347ac797..466e5562 100644 --- a/custom_components/frigate/manifest.json +++ b/custom_components/frigate/manifest.json @@ -14,5 +14,5 @@ "iot_class": "local_push", "issue_tracker": "https://github.com/blakeblackshear/frigate-hass-integration/issues", "requirements": ["pytz"], - "version": "5.0.1" + "version": "5.1.0" }