From 2d510bfe0de04c549cb2b6b7e42dca3acb3821aa Mon Sep 17 00:00:00 2001 From: nachonam Date: Wed, 26 Apr 2023 00:03:39 +0200 Subject: [PATCH] Add camera platform to Freebox (#88104) * Add Freebox cameras * Apply suggestions from code review add code corrections after PR review Co-authored-by: Quentame * Update base_class.py * add some code syntax corrections add unit tests * add unit tests * add syntax changes * Update homeassistant/components/freebox/router.py Co-authored-by: Quentame * Update homeassistant/components/freebox/router.py Co-authored-by: Quentame * Update homeassistant/components/freebox/base_class.py Co-authored-by: Quentame * Update homeassistant/components/freebox/router.py Co-authored-by: Quentame * clear code and add minor changes * correct syntax error and check home granted access * typing functions * Update tests/components/freebox/conftest.py don't needed, and will fix tests. Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py Rename _volume_micro variable Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py Use const not literal Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py set to true not needed Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py use _attr_supported_features instead _supported_features Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py overload the entity with command_flip property and set_flip not needed Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py Cameras does not default to False, Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py delete this function because is not needed Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py Co-authored-by: Quentame * consts, rollback _command flip is protected var * VALUE_NOT_SET does not exists anymore * Use HOME_COMPATIBLE_PLATFORMS * Rename FreeboxHomeBaseClass to FreeboxHomeEntity * Update Freebox Home comment * Use CATEGORY_TO_MODEL to set model attr of FreeboxHomeEntity * Use Home API from the router * Add SERVICE_FLIP const * Use SERVICE_FLIP const * Fix typo in HOME_COMPATIBLE_PLATFORMS * fix somme code issues * use SERVICE_FLIP (lost in merge) * use _attr_device_info * clear code * HOME_COMPATIBLE_PLATFORMS is a list * Update homeassistant/components/freebox/home_base.py Co-authored-by: Quentame * Update homeassistant/components/freebox/home_base.py Co-authored-by: Quentame * Update homeassistant/components/freebox/config_flow.py Co-authored-by: Quentame * Update homeassistant/components/freebox/home_base.py Co-authored-by: Quentame * Update homeassistant/components/freebox/home_base.py Co-authored-by: Quentame * clear config_flow permission * Update homeassistant/components/freebox/home_base.py Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py Co-authored-by: Quentame * add untested files to. coveragerc * clear unused attributes * add not tested file camera.py * clear unusued const * add extra_state_attributes * Update .coveragerc Co-authored-by: Quentame * Update homeassistant/components/freebox/camera.py Co-authored-by: Quentame * fetch _flip * del flip service * add device_info via_device * Update .coveragerc * Update .coveragerc * Update .coveragerc * Update .coveragerc * Remove flip reference * Fix issue on router without Home API * Fix "Home access is not granted" log repeats every 30s * Fix sensor device_info --------- Co-authored-by: Quentame --- .coveragerc | 3 + homeassistant/components/freebox/camera.py | 122 ++ .../components/freebox/config_flow.py | 10 +- homeassistant/components/freebox/const.py | 26 +- homeassistant/components/freebox/home_base.py | 131 ++ .../components/freebox/manifest.json | 1 + homeassistant/components/freebox/router.py | 50 +- homeassistant/components/freebox/sensor.py | 25 +- tests/components/freebox/conftest.py | 3 + tests/components/freebox/const.py | 1650 +++++++++++++++++ 10 files changed, 1998 insertions(+), 23 deletions(-) create mode 100644 homeassistant/components/freebox/camera.py create mode 100644 homeassistant/components/freebox/home_base.py diff --git a/.coveragerc b/.coveragerc index f1687c2e277..4827d93ed52 100644 --- a/.coveragerc +++ b/.coveragerc @@ -386,7 +386,10 @@ omit = homeassistant/components/foscam/camera.py homeassistant/components/foursquare/* homeassistant/components/free_mobile/notify.py + homeassistant/components/freebox/camera.py homeassistant/components/freebox/device_tracker.py + homeassistant/components/freebox/home_base.py + homeassistant/components/freebox/router.py homeassistant/components/freebox/sensor.py homeassistant/components/freebox/switch.py homeassistant/components/fritz/common.py diff --git a/homeassistant/components/freebox/camera.py b/homeassistant/components/freebox/camera.py new file mode 100644 index 00000000000..9e833aca18b --- /dev/null +++ b/homeassistant/components/freebox/camera.py @@ -0,0 +1,122 @@ +"""Support for Freebox cameras.""" +from __future__ import annotations + +import logging +from typing import Any + +from homeassistant.components.camera import CameraEntityFeature +from homeassistant.components.ffmpeg.camera import ( + CONF_EXTRA_ARGUMENTS, + CONF_INPUT, + DEFAULT_ARGUMENTS, + FFmpegCamera, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_NAME, Platform +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import entity_platform +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from .const import ATTR_DETECTION, DOMAIN +from .home_base import FreeboxHomeEntity +from .router import FreeboxRouter + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up cameras.""" + router = hass.data[DOMAIN][entry.unique_id] + tracked: set = set() + + @callback + def update_callback(): + add_entities(hass, router, async_add_entities, tracked) + + router.listeners.append( + async_dispatcher_connect(hass, router.signal_home_device_new, update_callback) + ) + update_callback() + + entity_platform.async_get_current_platform() + + +@callback +def add_entities(hass: HomeAssistant, router, async_add_entities, tracked): + """Add new cameras from the router.""" + new_tracked = [] + + for nodeid, node in router.home_devices.items(): + if (node["category"] != Platform.CAMERA) or (nodeid in tracked): + continue + new_tracked.append(FreeboxCamera(hass, router, node)) + tracked.add(nodeid) + + if new_tracked: + async_add_entities(new_tracked, True) + + +class FreeboxCamera(FreeboxHomeEntity, FFmpegCamera): + """Representation of a Freebox camera.""" + + def __init__( + self, hass: HomeAssistant, router: FreeboxRouter, node: dict[str, Any] + ) -> None: + """Initialize a camera.""" + + super().__init__(hass, router, node) + device_info = { + CONF_NAME: node["label"].strip(), + CONF_INPUT: node["props"]["Stream"], + CONF_EXTRA_ARGUMENTS: DEFAULT_ARGUMENTS, + } + FFmpegCamera.__init__(self, hass, device_info) + + self._supported_features = ( + CameraEntityFeature.ON_OFF | CameraEntityFeature.STREAM + ) + + self._command_motion_detection = self.get_command_id( + node["type"]["endpoints"], ATTR_DETECTION + ) + self._attr_extra_state_attributes = {} + self.update_node(node) + + async def async_enable_motion_detection(self) -> None: + """Enable motion detection in the camera.""" + await self.set_home_endpoint_value(self._command_motion_detection, True) + self._attr_motion_detection_enabled = True + + async def async_disable_motion_detection(self) -> None: + """Disable motion detection in camera.""" + await self.set_home_endpoint_value(self._command_motion_detection, False) + self._attr_motion_detection_enabled = False + + async def async_update_signal(self) -> None: + """Update the camera node.""" + self.update_node(self._router.home_devices[self._id]) + self.async_write_ha_state() + + def update_node(self, node): + """Update params.""" + self._name = node["label"].strip() + + # Get status + if self._node["status"] == "active": + self._attr_is_streaming = True + else: + self._attr_is_streaming = False + + # Parse all endpoints values + for endpoint in filter( + lambda x: (x["ep_type"] == "signal"), node["show_endpoints"] + ): + self._attr_extra_state_attributes[endpoint["name"]] = endpoint["value"] + + # Get motion detection status + self._attr_motion_detection_enabled = self._attr_extra_state_attributes[ + ATTR_DETECTION + ] diff --git a/homeassistant/components/freebox/config_flow.py b/homeassistant/components/freebox/config_flow.py index dbee01c4e7d..af641b5430c 100644 --- a/homeassistant/components/freebox/config_flow.py +++ b/homeassistant/components/freebox/config_flow.py @@ -22,7 +22,7 @@ class FreeboxFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): def __init__(self) -> None: """Initialize Freebox config flow.""" - self._host = None + self._host: str self._port = None def _show_setup_form(self, user_input=None, errors=None): @@ -42,9 +42,9 @@ class FreeboxFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): errors=errors or {}, ) - async def async_step_user(self, user_input=None): + async def async_step_user(self, user_input=None) -> FlowResult: """Handle a flow initiated by the user.""" - errors = {} + errors: dict[str, str] = {} if user_input is None: return self._show_setup_form(user_input, errors) @@ -58,7 +58,7 @@ class FreeboxFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): return await self.async_step_link() - async def async_step_link(self, user_input=None): + async def async_step_link(self, user_input=None) -> FlowResult: """Attempt to link with the Freebox router. Given a configured host, will ask the user to press the button @@ -102,7 +102,7 @@ class FreeboxFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): return self.async_show_form(step_id="link", errors=errors) - async def async_step_import(self, user_input=None): + async def async_step_import(self, user_input=None) -> FlowResult: """Import a config entry.""" return await self.async_step_user(user_input) diff --git a/homeassistant/components/freebox/const.py b/homeassistant/components/freebox/const.py index 32cf407f2a9..767cb94de48 100644 --- a/homeassistant/components/freebox/const.py +++ b/homeassistant/components/freebox/const.py @@ -16,7 +16,13 @@ APP_DESC = { } API_VERSION = "v6" -PLATFORMS = [Platform.BUTTON, Platform.DEVICE_TRACKER, Platform.SENSOR, Platform.SWITCH] +PLATFORMS = [ + Platform.BUTTON, + Platform.DEVICE_TRACKER, + Platform.SENSOR, + Platform.SWITCH, + Platform.CAMERA, +] DEFAULT_DEVICE_NAME = "Unknown device" @@ -27,7 +33,6 @@ STORAGE_VERSION = 1 CONNECTION_SENSORS_KEYS = {"rate_down", "rate_up"} - # Icons DEVICE_ICONS = { "freebox_delta": "mdi:television-guide", @@ -48,3 +53,20 @@ DEVICE_ICONS = { "vg_console": "mdi:gamepad-variant", "workstation": "mdi:desktop-tower-monitor", } + +ATTR_DETECTION = "detection" + + +CATEGORY_TO_MODEL = { + "pir": "F-HAPIR01A", + "camera": "F-HACAM01A", + "dws": "F-HADWS01A", + "kfb": "F-HAKFB01A", + "alarm": "F-MSEC07A", + "rts": "RTS", + "iohome": "IOHome", +} + +HOME_COMPATIBLE_PLATFORMS = [ + Platform.CAMERA, +] diff --git a/homeassistant/components/freebox/home_base.py b/homeassistant/components/freebox/home_base.py new file mode 100644 index 00000000000..c74f072a5be --- /dev/null +++ b/homeassistant/components/freebox/home_base.py @@ -0,0 +1,131 @@ +"""Support for Freebox base features.""" +from __future__ import annotations + +import logging +from typing import Any + +from homeassistant.core import HomeAssistant +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity import DeviceInfo, Entity + +from .const import CATEGORY_TO_MODEL, DOMAIN +from .router import FreeboxRouter + +_LOGGER = logging.getLogger(__name__) + + +class FreeboxHomeEntity(Entity): + """Representation of a Freebox base entity.""" + + def __init__( + self, + hass: HomeAssistant, + router: FreeboxRouter, + node: dict[str, Any], + sub_node: dict[str, Any] | None = None, + ) -> None: + """Initialize a Freebox Home entity.""" + self._hass = hass + self._router = router + self._node = node + self._sub_node = sub_node + self._id = node["id"] + self._attr_name = node["label"].strip() + self._device_name = self._attr_name + self._attr_unique_id = f"{self._router.mac}-node_{self._id}" + + if sub_node is not None: + self._attr_name += " " + sub_node["label"].strip() + self._attr_unique_id += "-" + sub_node["name"].strip() + + self._available = True + self._firmware = node["props"].get("FwVersion") + self._manufacturer = "Freebox SAS" + self._remove_signal_update: Any + + self._model = CATEGORY_TO_MODEL.get(node["category"]) + if self._model is None: + if node["type"].get("inherit") == "node::rts": + self._manufacturer = "Somfy" + self._model = CATEGORY_TO_MODEL.get("rts") + elif node["type"].get("inherit") == "node::ios": + self._manufacturer = "Somfy" + self._model = CATEGORY_TO_MODEL.get("iohome") + + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, self._id)}, + manufacturer=self._manufacturer, + model=self._model, + name=self._device_name, + sw_version=self._firmware, + via_device=( + DOMAIN, + router.mac, + ), + ) + + async def async_update_signal(self): + """Update signal.""" + self._node = self._router.home_devices[self._id] + # Update name + if self._sub_node is None: + self._attr_name = self._node["label"].strip() + else: + self._attr_name = ( + self._node["label"].strip() + " " + self._sub_node["label"].strip() + ) + self.async_write_ha_state() + + async def set_home_endpoint_value(self, command_id: Any, value=None) -> None: + """Set Home endpoint value.""" + if command_id is None: + _LOGGER.error("Unable to SET a value through the API. Command is None") + return + await self._router.home.set_home_endpoint_value( + self._id, command_id, {"value": value} + ) + + def get_command_id(self, nodes, name) -> int | None: + """Get the command id.""" + node = next( + filter(lambda x: (x["name"] == name), nodes), + None, + ) + if not node: + _LOGGER.warning("The Freebox Home device has no value for: %s", name) + return None + return node["id"] + + async def async_added_to_hass(self): + """Register state update callback.""" + self.remove_signal_update( + async_dispatcher_connect( + self._hass, + self._router.signal_home_device_update, + self.async_update_signal, + ) + ) + + async def async_will_remove_from_hass(self): + """When entity will be removed from hass.""" + self._remove_signal_update() + + def remove_signal_update(self, dispacher: Any): + """Register state update callback.""" + self._remove_signal_update = dispacher + + def get_value(self, ep_type, name): + """Get the value.""" + node = next( + filter( + lambda x: (x["name"] == name and x["ep_type"] == ep_type), + self._node["show_endpoints"], + ), + None, + ) + if not node: + _LOGGER.warning( + "The Freebox Home device has no node for: " + ep_type + "/" + name + ) + return None + return node.get("value") diff --git a/homeassistant/components/freebox/manifest.json b/homeassistant/components/freebox/manifest.json index 637f7050bf6..ad7da1703b8 100644 --- a/homeassistant/components/freebox/manifest.json +++ b/homeassistant/components/freebox/manifest.json @@ -3,6 +3,7 @@ "name": "Freebox", "codeowners": ["@hacf-fr", "@Quentame"], "config_flow": true, + "dependencies": ["ffmpeg"], "documentation": "https://www.home-assistant.io/integrations/freebox", "iot_class": "local_polling", "loggers": ["freebox_api"], diff --git a/homeassistant/components/freebox/router.py b/homeassistant/components/freebox/router.py index 0fb0f10a27d..5622da48e67 100644 --- a/homeassistant/components/freebox/router.py +++ b/homeassistant/components/freebox/router.py @@ -4,14 +4,16 @@ from __future__ import annotations from collections.abc import Mapping from contextlib import suppress from datetime import datetime +import logging import os from pathlib import Path from typing import Any from freebox_api import Freepybox from freebox_api.api.call import Call +from freebox_api.api.home import Home from freebox_api.api.wifi import Wifi -from freebox_api.exceptions import NotOpenError +from freebox_api.exceptions import HttpRequestError, NotOpenError from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PORT @@ -27,10 +29,13 @@ from .const import ( APP_DESC, CONNECTION_SENSORS_KEYS, DOMAIN, + HOME_COMPATIBLE_PLATFORMS, STORAGE_KEY, STORAGE_VERSION, ) +_LOGGER = logging.getLogger(__name__) + async def get_api(hass: HomeAssistant, host: str) -> Freepybox: """Get the Freebox API.""" @@ -70,11 +75,15 @@ class FreeboxRouter: self.sensors_temperature: dict[str, int] = {} self.sensors_connection: dict[str, float] = {} self.call_list: list[dict[str, Any]] = [] + self.home_granted = True + self.home_devices: dict[str, Any] = {} + self.listeners: list[dict[str, Any]] = [] async def update_all(self, now: datetime | None = None) -> None: """Update all Freebox platforms.""" await self.update_device_trackers() await self.update_sensors() + await self.update_home_devices() async def update_device_trackers(self) -> None: """Update Freebox devices.""" @@ -146,6 +155,30 @@ class FreeboxRouter: for fbx_disk in fbx_disks: self.disks[fbx_disk["id"]] = fbx_disk + async def update_home_devices(self) -> None: + """Update Home devices (alarm, light, sensor, switch, remote ...).""" + if not self.home_granted: + return + + try: + home_nodes: list[Any] = await self.home.get_home_nodes() or [] + except HttpRequestError: + self.home_granted = False + _LOGGER.warning("Home access is not granted") + return + + new_device = False + for home_node in home_nodes: + if home_node["category"] in HOME_COMPATIBLE_PLATFORMS: + if self.home_devices.get(home_node["id"]) is None: + new_device = True + self.home_devices[home_node["id"]] = home_node + + async_dispatcher_send(self.hass, self.signal_home_device_update) + + if new_device: + async_dispatcher_send(self.hass, self.signal_home_device_new) + async def reboot(self) -> None: """Reboot the Freebox.""" await self._api.system.reboot() @@ -172,6 +205,11 @@ class FreeboxRouter: """Event specific per Freebox entry to signal new device.""" return f"{DOMAIN}-{self._host}-device-new" + @property + def signal_home_device_new(self) -> str: + """Event specific per Freebox entry to signal new home device.""" + return f"{DOMAIN}-{self._host}-home-device-new" + @property def signal_device_update(self) -> str: """Event specific per Freebox entry to signal updates in devices.""" @@ -182,6 +220,11 @@ class FreeboxRouter: """Event specific per Freebox entry to signal updates in sensors.""" return f"{DOMAIN}-{self._host}-sensor-update" + @property + def signal_home_device_update(self) -> str: + """Event specific per Freebox entry to signal update in home devices.""" + return f"{DOMAIN}-{self._host}-home-device-update" + @property def sensors(self) -> dict[str, Any]: """Return sensors.""" @@ -196,3 +239,8 @@ class FreeboxRouter: def wifi(self) -> Wifi: """Return the wifi.""" return self._api.wifi + + @property + def home(self) -> Home: + """Return the home.""" + return self._api.home diff --git a/homeassistant/components/freebox/sensor.py b/homeassistant/components/freebox/sensor.py index 4d5ba490faf..488d2d48f8c 100644 --- a/homeassistant/components/freebox/sensor.py +++ b/homeassistant/components/freebox/sensor.py @@ -113,6 +113,7 @@ class FreeboxSensor(SensorEntity): self.entity_description = description self._router = router self._attr_unique_id = f"{router.mac} {description.name}" + self._attr_device_info = router.device_info @callback def async_update_state(self) -> None: @@ -123,11 +124,6 @@ class FreeboxSensor(SensorEntity): else: self._attr_native_value = state - @property - def device_info(self) -> DeviceInfo: - """Return the device information.""" - return self._router.device_info - @callback def async_on_demand_update(self): """Update state.""" @@ -193,19 +189,18 @@ class FreeboxDiskSensor(FreeboxSensor): self._disk = disk self._partition = partition self._attr_name = f"{partition['label']} {description.name}" - self._attr_unique_id = f"{self._router.mac} {description.key} {self._disk['id']} {self._partition['id']}" + self._attr_unique_id = ( + f"{router.mac} {description.key} {disk['id']} {partition['id']}" + ) - @property - def device_info(self) -> DeviceInfo: - """Return the device information.""" - return DeviceInfo( - identifiers={(DOMAIN, self._disk["id"])}, - model=self._disk["model"], - name=f"Disk {self._disk['id']}", - sw_version=self._disk["firmware"], + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, disk["id"])}, + model=disk["model"], + name=f"Disk {disk['id']}", + sw_version=disk["firmware"], via_device=( DOMAIN, - self._router.mac, + router.mac, ), ) diff --git a/tests/components/freebox/conftest.py b/tests/components/freebox/conftest.py index 66718155af4..7bf1cbfe7a4 100644 --- a/tests/components/freebox/conftest.py +++ b/tests/components/freebox/conftest.py @@ -8,6 +8,7 @@ from homeassistant.helpers import device_registry as dr from .const import ( DATA_CALL_GET_CALLS_LOG, DATA_CONNECTION_GET_STATUS, + DATA_HOME_GET_NODES, DATA_LAN_GET_HOSTS_LIST, DATA_STORAGE_GET_DISKS, DATA_SYSTEM_GET_CONFIG, @@ -55,6 +56,8 @@ def mock_router(mock_device_registry_devices): # sensor instance.call.get_calls_log = AsyncMock(return_value=DATA_CALL_GET_CALLS_LOG) instance.storage.get_disks = AsyncMock(return_value=DATA_STORAGE_GET_DISKS) + # home devices + instance.home.get_home_nodes = AsyncMock(return_value=DATA_HOME_GET_NODES) instance.connection.get_status = AsyncMock( return_value=DATA_CONNECTION_GET_STATUS ) diff --git a/tests/components/freebox/const.py b/tests/components/freebox/const.py index 25402cbcdef..96fe96c19c5 100644 --- a/tests/components/freebox/const.py +++ b/tests/components/freebox/const.py @@ -410,3 +410,1653 @@ DATA_LAN_GET_HOSTS_LIST = [ "primary_name": "iPhoneofQuentin", }, ] + + +DATA_HOME_GET_NODES = [ + { + "adapter": 2, + "area": 38, + "category": "camera", + "group": {"label": "Salon"}, + "id": 16, + "label": "Caméra II", + "name": "node_16", + "props": { + "Ip": "192.169.0.2", + "Login": "camfreebox", + "Mac": "34:2d:f2:e5:9d:ff", + "Pass": "xxxxx", + "Stream": "http://freeboxcam:mv...tream.m3u8", + }, + "show_endpoints": [ + { + "category": "", + "ep_type": "slot", + "id": 0, + "label": "Détection", + "name": "detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 1, + "label": "Activé avec l'alarme", + "name": "activation", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 2, + "label": "Haute qualité vidéo", + "name": "quality", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 3, + "label": "Sensibilité", + "name": "sensitivity", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 4, + "label": "Seuil", + "name": "threshold", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 5, + "label": "Retourner verticalement", + "name": "flip", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 6, + "label": "Horodatage", + "name": "timestamp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 7, + "label": "Volume du micro", + "name": "volume", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 9, + "label": "Détection de bruit", + "name": "sound_detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 10, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 11, + "label": "Flux rtsp", + "name": "rtsp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 12, + "label": "Emplacement des vidéos", + "name": "disk", + "ui": {"access": "rw", "display": "disk"}, + "value": "", + "value_type": "string", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 13, + "label": "Détection ", + "name": "detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/xxxx.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 14, + "label": "Activé avec l'alarme", + "name": "activation", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Ce réglage permet d'activer l'enregistrement de la caméra uniquement quand l'alarme est activée.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/alert_toggle.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 15, + "label": "Haute qualité vidéo", + "name": "quality", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Les vidéos seront enregistrées en 720p en haute qualité et 480p en qualité réduite.\r\n\r\nNous vous recommandons de laisser cette option désactivée si vous avez des difficultés de lecture des fichiers à distance.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Flux.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 16, + "label": "Sensibilité", + "name": "sensitivity", + "refresh": 2000, + "ui": { + "access": "r", + "description": "La sensibilité définit la faculté d'un pixel à être sensible aux changements.\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute, plus les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 17, + "label": "Seuil", + "name": "threshold", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Le seuil définit le nombre de pixels devant changer pour déclencher la détection .\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute moins les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 2, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 18, + "label": "Retourner verticalement", + "name": "flip", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Retour.png", + }, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 19, + "label": "Horodatage", + "name": "timestamp", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Horloge.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 20, + "label": "Volume du micro", + "name": "volume", + "refresh": 2000, + "ui": { + "access": "r", + "display": "slider", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + "range": [...], + }, + "value": 100, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 22, + "label": "Détection de bruit", + "name": "sound_detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 23, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Quatre réglages sont disponibles pour la sensibilité du micro (1-4).\r\n\r\nPlus cette valeur est haute, plus les enregistrements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 24, + "label": "Flux rtsp", + "name": "rtsp", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Active le flux RTSP à l'adresse rtsp://ip_camera/live", + "display": "toggle", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 25, + "label": "Niveau de réception", + "name": "rssi", + "refresh": 2000, + "ui": { + "access": "r", + "display": "icon", + "icon_range": [...], + "icon_url": "/resources/images/home/pictos/reception_%.png", + "range": [...], + "status_text_range": [...], + "unit": "dB", + }, + "value": -75, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 26, + "label": "Emplacement des vidéos", + "name": "disk", + "refresh": 2000, + "ui": { + "access": "r", + "display": "disk", + "icon_url": "/resources/images/home/pictos/directory.png", + }, + "value": "Freebox", + "value_type": "string", + "visibility": "normal", + }, + ], + "signal_links": [], + "slot_links": [{...}], + "status": "active", + "type": { + "abstract": False, + "endpoints": [ + { + "category": "", + "ep_type": "slot", + "id": 0, + "label": "Détection ", + "name": "detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 1, + "label": "Activé avec l'alarme", + "name": "activation", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 2, + "label": "Haute qualité vidéo", + "name": "quality", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 3, + "label": "Sensibilité", + "name": "sensitivity", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 4, + "label": "Seuil", + "name": "threshold", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 5, + "label": "Retourner verticalement", + "name": "flip", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 6, + "label": "Horodatage", + "name": "timestamp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 7, + "label": "Volume du micro", + "name": "volume", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 9, + "label": "Détection de bruit", + "name": "sound_detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 10, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 11, + "label": "Flux rtsp", + "name": "rtsp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 12, + "label": "Emplacement des vidéos", + "name": "disk", + "ui": {"access": "rw", "display": "disk"}, + "value": "", + "value_type": "string", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 13, + "label": "Détection ", + "name": "detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/xxxx.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 14, + "label": "Activé avec l'alarme", + "name": "activation", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Ce réglage permet d'activer l'enregistrement de la caméra uniquement quand l'alarme est activée.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/alert_toggle.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 15, + "label": "Haute qualité vidéo", + "name": "quality", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Les vidéos seront enregistrées en 720p en haute qualité et 480p en qualité réduite.\r\n\r\nNous vous recommandons de laisser cette option désactivée si vous avez des difficultés de lecture des fichiers à distance.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Flux.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 16, + "label": "Sensibilité", + "name": "sensitivity", + "refresh": 2000, + "ui": { + "access": "r", + "description": "La sensibilité définit la faculté d'un pixel à être sensible aux changements.\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute, plus les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 17, + "label": "Seuil", + "name": "threshold", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Le seuil définit le nombre de pixels devant changer pour déclencher la détection .\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute moins les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 2, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 18, + "label": "Retourner verticalement", + "name": "flip", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Retour.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 19, + "label": "Horodatage", + "name": "timestamp", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Horloge.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 20, + "label": "Volume du micro", + "name": "volume", + "refresh": 2000, + "ui": { + "access": "r", + "display": "slider", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + "range": [...], + }, + "value": 80, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 22, + "label": "Détection de bruit", + "name": "sound_detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 23, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Quatre réglages sont disponibles pour la sensibilité du micro (1-4).\r\n\r\nPlus cette valeur est haute, plus les enregistrements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 24, + "label": "Flux rtsp", + "name": "rtsp", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Active le flux RTSP à l'adresse rtsp://ip_camera/live", + "display": "toggle", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 25, + "label": "Niveau de réception", + "name": "rssi", + "refresh": 2000, + "ui": { + "access": "r", + "display": "icon", + "icon_range": [...], + "icon_url": "/resources/images/home/pictos/reception_%.png", + "range": [...], + "status_text_range": [...], + "unit": "dB", + }, + "value": -49, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 26, + "label": "Emplacement des vidéos", + "name": "disk", + "refresh": 2000, + "ui": { + "access": "r", + "display": "disk", + "icon_url": "/resources/images/home/pictos/directory.png", + }, + "value": "Freebox", + "value_type": "string", + "visibility": "normal", + }, + ], + "generic": False, + "icon": "/resources/images/ho...camera.png", + "inherit": "node::cam", + "label": "Caméra Freebox", + "name": "node::cam::freebox", + "params": {}, + "physical": True, + }, + }, + { + "adapter": 1, + "area": 38, + "category": "camera", + "group": {"label": "Salon"}, + "id": 15, + "label": "Caméra I", + "name": "node_15", + "props": { + "Ip": "192.169.0.2", + "Login": "camfreebox", + "Mac": "34:2d:f2:e5:9d:ff", + "Pass": "xxxxx", + "Stream": "http://freeboxcam:mv...tream.m3u8", + }, + "show_endpoints": [ + { + "category": "", + "ep_type": "slot", + "id": 0, + "label": "Détection ", + "name": "detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 1, + "label": "Activé avec l'alarme", + "name": "activation", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 2, + "label": "Haute qualité vidéo", + "name": "quality", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 3, + "label": "Sensibilité", + "name": "sensitivity", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 4, + "label": "Seuil", + "name": "threshold", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 5, + "label": "Retourner verticalement", + "name": "flip", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 6, + "label": "Horodatage", + "name": "timestamp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 7, + "label": "Volume du micro", + "name": "volume", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 9, + "label": "Détection de bruit", + "name": "sound_detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 10, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 11, + "label": "Flux rtsp", + "name": "rtsp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 12, + "label": "Emplacement des vidéos", + "name": "disk", + "ui": {"access": "rw", "display": "disk"}, + "value": "", + "value_type": "string", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 13, + "label": "Détection ", + "name": "detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/xxxx.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 14, + "label": "Activé avec l'alarme", + "name": "activation", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Ce réglage permet d'activer l'enregistrement de la caméra uniquement quand l'alarme est activée.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/alert_toggle.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 15, + "label": "Haute qualité vidéo", + "name": "quality", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Les vidéos seront enregistrées en 720p en haute qualité et 480p en qualité réduite.\r\n\r\nNous vous recommandons de laisser cette option désactivée si vous avez des difficultés de lecture des fichiers à distance.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Flux.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 16, + "label": "Sensibilité", + "name": "sensitivity", + "refresh": 2000, + "ui": { + "access": "r", + "description": "La sensibilité définit la faculté d'un pixel à être sensible aux changements.\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute, plus les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 17, + "label": "Seuil", + "name": "threshold", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Le seuil définit le nombre de pixels devant changer pour déclencher la détection .\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute moins les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 2, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 18, + "label": "Retourner verticalement", + "name": "flip", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Retour.png", + }, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 19, + "label": "Horodatage", + "name": "timestamp", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Horloge.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 20, + "label": "Volume du micro", + "name": "volume", + "refresh": 2000, + "ui": { + "access": "r", + "display": "slider", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + "range": [...], + }, + "value": 100, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 22, + "label": "Détection de bruit", + "name": "sound_detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 23, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Quatre réglages sont disponibles pour la sensibilité du micro (1-4).\r\n\r\nPlus cette valeur est haute, plus les enregistrements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 24, + "label": "Flux rtsp", + "name": "rtsp", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Active le flux RTSP à l'adresse rtsp://ip_camera/live", + "display": "toggle", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 25, + "label": "Niveau de réception", + "name": "rssi", + "refresh": 2000, + "ui": { + "access": "r", + "display": "icon", + "icon_range": [...], + "icon_url": "/resources/images/home/pictos/reception_%.png", + "range": [...], + "status_text_range": [...], + "unit": "dB", + }, + "value": -75, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 26, + "label": "Emplacement des vidéos", + "name": "disk", + "refresh": 2000, + "ui": { + "access": "r", + "display": "disk", + "icon_url": "/resources/images/home/pictos/directory.png", + }, + "value": "Freebox", + "value_type": "string", + "visibility": "normal", + }, + ], + "signal_links": [], + "slot_links": [{...}], + "status": "active", + "type": { + "abstract": False, + "endpoints": [ + { + "category": "", + "ep_type": "slot", + "id": 0, + "label": "Détection ", + "name": "detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 1, + "label": "Activé avec l'alarme", + "name": "activation", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 2, + "label": "Haute qualité vidéo", + "name": "quality", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 3, + "label": "Sensibilité", + "name": "sensitivity", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 4, + "label": "Seuil", + "name": "threshold", + "ui": {"access": "rw", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 5, + "label": "Retourner verticalement", + "name": "flip", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 6, + "label": "Horodatage", + "name": "timestamp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 7, + "label": "Volume du micro", + "name": "volume", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 9, + "label": "Détection de bruit", + "name": "sound_detection", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 10, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "ui": {"access": "w", "display": "slider", "range": [...]}, + "value": 0, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 11, + "label": "Flux rtsp", + "name": "rtsp", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 12, + "label": "Emplacement des vidéos", + "name": "disk", + "ui": {"access": "rw", "display": "disk"}, + "value": "", + "value_type": "string", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 13, + "label": "Détection ", + "name": "detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/xxxx.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 14, + "label": "Activé avec l'alarme", + "name": "activation", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Ce réglage permet d'activer l'enregistrement de la caméra uniquement quand l'alarme est activée.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/alert_toggle.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 15, + "label": "Haute qualité vidéo", + "name": "quality", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Les vidéos seront enregistrées en 720p en haute qualité et 480p en qualité réduite.\r\n\r\nNous vous recommandons de laisser cette option désactivée si vous avez des difficultés de lecture des fichiers à distance.", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Flux.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 16, + "label": "Sensibilité", + "name": "sensitivity", + "refresh": 2000, + "ui": { + "access": "r", + "description": "La sensibilité définit la faculté d'un pixel à être sensible aux changements.\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute, plus les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 17, + "label": "Seuil", + "name": "threshold", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Le seuil définit le nombre de pixels devant changer pour déclencher la détection .\r\n\r\nQuatre réglages sont disponibles (1-4). Plus cette valeur est haute moins les déclenchements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 2, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 18, + "label": "Retourner verticalement", + "name": "flip", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Retour.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 19, + "label": "Horodatage", + "name": "timestamp", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/Horloge.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 20, + "label": "Volume du micro", + "name": "volume", + "refresh": 2000, + "ui": { + "access": "r", + "display": "slider", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + "range": [...], + }, + "value": 80, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 22, + "label": "Détection de bruit", + "name": "sound_detection", + "refresh": 2000, + "ui": { + "access": "r", + "display": "toggle", + "icon_url": "/resources/images/home/pictos/commande_vocale.png", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 23, + "label": "Sensibilité du micro", + "name": "sound_trigger", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Quatre réglages sont disponibles pour la sensibilité du micro (1-4).\r\n\r\nPlus cette valeur est haute, plus les enregistrements seront fréquents.", + "display": "slider", + "range": [...], + }, + "value": 3, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 24, + "label": "Flux rtsp", + "name": "rtsp", + "refresh": 2000, + "ui": { + "access": "r", + "description": "Active le flux RTSP à l'adresse rtsp://ip_camera/live", + "display": "toggle", + }, + "value": True, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 25, + "label": "Niveau de réception", + "name": "rssi", + "refresh": 2000, + "ui": { + "access": "r", + "display": "icon", + "icon_range": [...], + "icon_url": "/resources/images/home/pictos/reception_%.png", + "range": [...], + "status_text_range": [...], + "unit": "dB", + }, + "value": -49, + "value_type": "int", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 26, + "label": "Emplacement des vidéos", + "name": "disk", + "refresh": 2000, + "ui": { + "access": "r", + "display": "disk", + "icon_url": "/resources/images/home/pictos/directory.png", + }, + "value": "Freebox", + "value_type": "string", + "visibility": "normal", + }, + ], + "generic": False, + "icon": "/resources/images/ho...camera.png", + "inherit": "node::cam", + "label": "Caméra Freebox", + "name": "node::cam::freebox", + "params": {}, + "physical": True, + }, + }, + { + "adapter": 5, + "category": "kfb", + "group": {"label": ""}, + "id": 9, + "label": "Télécommande I", + "name": "node_9", + "props": { + "Address": 5, + "Challenge": "65ae6b4def41f3e3a5a77ec63e988", + "FwVersion": 29798318, + "Gateway": 1, + "ItemId": "e76c2b75a4a6e2", + }, + "show_endpoints": [{...}, {...}, {...}, {...}], + "signal_links": [{...}], + "slot_links": [], + "status": "active", + "type": { + "abstract": False, + "endpoints": [...], + "generic": False, + "icon": "/resources/images/home/pictos/telecommande.png", + "inherit": "node::domus", + "label": "Télécommande pour alarme", + "name": "node::domus::sercomm::keyfob", + "params": {}, + "physical": True, + }, + }, + { + "adapter": 5, + "area": 40, + "category": "dws", + "group": {"label": "Entrée"}, + "id": 11, + "label": "dws i", + "name": "node_11", + "props": { + "Address": 6, + "Challenge": "964a2dddf2c40c3e2384f66d2", + "FwVersion": 29798220, + "Gateway": 1, + "ItemId": "9eff759dd553de7", + }, + "show_endpoints": [ + { + "category": "", + "ep_type": "slot", + "id": 0, + "label": "Alarme principale", + "name": "alarm1", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 1, + "label": "Alarme secondaire", + "name": "alarm2", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "slot", + "id": 2, + "label": "Zone temporisée", + "name": "timed", + "ui": {"access": "w", "display": "toggle"}, + "value": False, + "value_type": "bool", + "visibility": "normal", + }, + { + "category": "", + "ep_type": "signal", + "id": 8, + "label": "Niveau de Batterie", + "name": "battery", + "refresh": 2000, + "ui": { + "access": "r", + "display": "icon", + "icon_range": [...], + "icon_url": "/resources/images/home/pictos/batt_%.png", + "range": [...], + "status_text_range": [...], + "unit": "%", + }, + "value": 100, + "value_type": "int", + "visibility": "normal", + }, + ], + "signal_links": [{...}], + "slot_links": [], + "status": "active", + "type": { + "abstract": False, + "endpoints": [...], + "generic": False, + "icon": "/resources/images/home/pictos/detecteur_ouverture.png", + "inherit": "node::domus", + "label": "Détecteur d'ouverture de porte", + "name": "node::domus::sercomm::doorswitch", + "params": {}, + "physical": True, + }, + }, + { + "adapter": 5, + "area": 38, + "category": "pir", + "group": {"label": "Salon"}, + "id": 26, + "label": "Salon Détecteur s", + "name": "node_26", + "props": { + "Address": 9, + "Challenge": "ed2cc17f179862f5242256b3f597c367", + "FwVersion": 29871925, + "Gateway": 1, + "ItemId": "240d000f9fefe576", + }, + "show_endpoints": [ + {...}, + {...}, + {...}, + {...}, + {...}, + {...}, + {...}, + {...}, + {...}, + ], + "signal_links": [{...}], + "slot_links": [], + "status": "active", + "type": { + "abstract": False, + "endpoints": [...], + "generic": False, + "icon": "/resources/images/home/pictos/detecteur_xxxx.png", + "inherit": "node::domus", + "label": "Détecteur infrarouge", + "name": "node::domus::sercomm::pir", + "params": {}, + "physical": True, + }, + }, + { + "adapter": 10, + "area": 38, + "category": "shutter", + "group": {"label": "Salon"}, + "id": 150, + "label": "Shutter 1", + "name": "node_150", + "type": { + "inherit": "node::trs", + }, + }, + { + "adapter": 11, + "area": 38, + "category": "shutter", + "group": {"label": "Salon"}, + "id": 151, + "label": "Shutter 2", + "name": "node_151", + "type": { + "inherit": "node::ios", + }, + }, +]