mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 08:17:08 +00:00
Add Freebox Home alarm panel (#102607)
* add alarm control panel * optimize update node * Modify comment * move const to alarm * add alarm panel tests * tests modified * add file into coveragerc * Review: DATA_HOME_GET_VALUES -> DATA_HOME_PIR_GET_VALUES * Review: commands rename * Review: precise what "alarm2" is for features * Review: remove custom attributes & properties that exists in parent * Review: Avoid duplicates of async_write_ha_state() * make functions private * Review: initial state never works * Review: remove extra attrs * Review: fix tests * Fix tests * Remove line in .coveragerc --------- Co-authored-by: Quentame <polletquentin74@me.com>
This commit is contained in:
parent
9ea97fd8d2
commit
cf03f8338a
138
homeassistant/components/freebox/alarm_control_panel.py
Normal file
138
homeassistant/components/freebox/alarm_control_panel.py
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
"""Support for Freebox alarms."""
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.alarm_control_panel import (
|
||||||
|
AlarmControlPanelEntity,
|
||||||
|
AlarmControlPanelEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import (
|
||||||
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_ARMING,
|
||||||
|
STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_TRIGGERED,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .const import DOMAIN, FreeboxHomeCategory
|
||||||
|
from .home_base import FreeboxHomeEntity
|
||||||
|
from .router import FreeboxRouter
|
||||||
|
|
||||||
|
FREEBOX_TO_STATUS = {
|
||||||
|
"alarm1_arming": STATE_ALARM_ARMING,
|
||||||
|
"alarm2_arming": STATE_ALARM_ARMING,
|
||||||
|
"alarm1_armed": STATE_ALARM_ARMED_AWAY,
|
||||||
|
"alarm2_armed": STATE_ALARM_ARMED_NIGHT,
|
||||||
|
"alarm1_alert_timer": STATE_ALARM_TRIGGERED,
|
||||||
|
"alarm2_alert_timer": STATE_ALARM_TRIGGERED,
|
||||||
|
"alert": STATE_ALARM_TRIGGERED,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
|
) -> None:
|
||||||
|
"""Set up alarm panel."""
|
||||||
|
router: FreeboxRouter = hass.data[DOMAIN][entry.unique_id]
|
||||||
|
|
||||||
|
alarm_entities: list[AlarmControlPanelEntity] = []
|
||||||
|
|
||||||
|
for node in router.home_devices.values():
|
||||||
|
if node["category"] == FreeboxHomeCategory.ALARM:
|
||||||
|
alarm_entities.append(FreeboxAlarm(hass, router, node))
|
||||||
|
|
||||||
|
if alarm_entities:
|
||||||
|
async_add_entities(alarm_entities, True)
|
||||||
|
|
||||||
|
|
||||||
|
class FreeboxAlarm(FreeboxHomeEntity, AlarmControlPanelEntity):
|
||||||
|
"""Representation of a Freebox alarm."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, hass: HomeAssistant, router: FreeboxRouter, node: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Initialize an alarm."""
|
||||||
|
super().__init__(hass, router, node)
|
||||||
|
|
||||||
|
# Commands
|
||||||
|
self._command_trigger = self.get_command_id(
|
||||||
|
node["type"]["endpoints"], "slot", "trigger"
|
||||||
|
)
|
||||||
|
self._command_arm_away = self.get_command_id(
|
||||||
|
node["type"]["endpoints"], "slot", "alarm1"
|
||||||
|
)
|
||||||
|
self._command_arm_home = self.get_command_id(
|
||||||
|
node["type"]["endpoints"], "slot", "alarm2"
|
||||||
|
)
|
||||||
|
self._command_disarm = self.get_command_id(
|
||||||
|
node["type"]["endpoints"], "slot", "off"
|
||||||
|
)
|
||||||
|
self._command_state = self.get_command_id(
|
||||||
|
node["type"]["endpoints"], "signal", "state"
|
||||||
|
)
|
||||||
|
self._set_features(self._router.home_devices[self._id])
|
||||||
|
|
||||||
|
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
||||||
|
"""Send disarm command."""
|
||||||
|
if await self.set_home_endpoint_value(self._command_disarm):
|
||||||
|
self._set_state(STATE_ALARM_DISARMED)
|
||||||
|
|
||||||
|
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
||||||
|
"""Send arm away command."""
|
||||||
|
if await self.set_home_endpoint_value(self._command_arm_away):
|
||||||
|
self._set_state(STATE_ALARM_ARMING)
|
||||||
|
|
||||||
|
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
||||||
|
"""Send arm home command."""
|
||||||
|
if await self.set_home_endpoint_value(self._command_arm_home):
|
||||||
|
self._set_state(STATE_ALARM_ARMING)
|
||||||
|
|
||||||
|
async def async_alarm_trigger(self, code: str | None = None) -> None:
|
||||||
|
"""Send alarm trigger command."""
|
||||||
|
if await self.set_home_endpoint_value(self._command_trigger):
|
||||||
|
self._set_state(STATE_ALARM_TRIGGERED)
|
||||||
|
|
||||||
|
async def async_update_signal(self):
|
||||||
|
"""Update signal."""
|
||||||
|
state = await self.get_home_endpoint_value(self._command_state)
|
||||||
|
if state:
|
||||||
|
self._set_state(state)
|
||||||
|
|
||||||
|
def _set_features(self, node: dict[str, Any]) -> None:
|
||||||
|
"""Add alarm features."""
|
||||||
|
# Search if the arm home feature is present => has an "alarm2" endpoint
|
||||||
|
can_arm_home = False
|
||||||
|
for nodeid, local_node in self._router.home_devices.items():
|
||||||
|
if nodeid == local_node["id"]:
|
||||||
|
alarm2 = next(
|
||||||
|
filter(
|
||||||
|
lambda x: (x["name"] == "alarm2" and x["ep_type"] == "signal"),
|
||||||
|
local_node["show_endpoints"],
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if alarm2:
|
||||||
|
can_arm_home = alarm2["value"]
|
||||||
|
break
|
||||||
|
|
||||||
|
if can_arm_home:
|
||||||
|
self._attr_supported_features = (
|
||||||
|
AlarmControlPanelEntityFeature.ARM_AWAY
|
||||||
|
| AlarmControlPanelEntityFeature.ARM_HOME
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self._attr_supported_features = AlarmControlPanelEntityFeature.ARM_AWAY
|
||||||
|
|
||||||
|
def _set_state(self, state: str) -> None:
|
||||||
|
"""Update state."""
|
||||||
|
self._attr_state = FREEBOX_TO_STATUS.get(state)
|
||||||
|
if not self._attr_state:
|
||||||
|
self._attr_state = STATE_ALARM_DISARMED
|
||||||
|
self.async_write_ha_state()
|
@ -18,6 +18,7 @@ APP_DESC = {
|
|||||||
API_VERSION = "v6"
|
API_VERSION = "v6"
|
||||||
|
|
||||||
PLATFORMS = [
|
PLATFORMS = [
|
||||||
|
Platform.ALARM_CONTROL_PANEL,
|
||||||
Platform.BUTTON,
|
Platform.BUTTON,
|
||||||
Platform.DEVICE_TRACKER,
|
Platform.DEVICE_TRACKER,
|
||||||
Platform.SENSOR,
|
Platform.SENSOR,
|
||||||
@ -84,6 +85,7 @@ CATEGORY_TO_MODEL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HOME_COMPATIBLE_CATEGORIES = [
|
HOME_COMPATIBLE_CATEGORIES = [
|
||||||
|
FreeboxHomeCategory.ALARM,
|
||||||
FreeboxHomeCategory.CAMERA,
|
FreeboxHomeCategory.CAMERA,
|
||||||
FreeboxHomeCategory.DWS,
|
FreeboxHomeCategory.DWS,
|
||||||
FreeboxHomeCategory.IOHOME,
|
FreeboxHomeCategory.IOHOME,
|
||||||
|
@ -10,7 +10,7 @@ from .const import (
|
|||||||
DATA_CALL_GET_CALLS_LOG,
|
DATA_CALL_GET_CALLS_LOG,
|
||||||
DATA_CONNECTION_GET_STATUS,
|
DATA_CONNECTION_GET_STATUS,
|
||||||
DATA_HOME_GET_NODES,
|
DATA_HOME_GET_NODES,
|
||||||
DATA_HOME_GET_VALUES,
|
DATA_HOME_PIR_GET_VALUES,
|
||||||
DATA_LAN_GET_HOSTS_LIST,
|
DATA_LAN_GET_HOSTS_LIST,
|
||||||
DATA_STORAGE_GET_DISKS,
|
DATA_STORAGE_GET_DISKS,
|
||||||
DATA_STORAGE_GET_RAIDS,
|
DATA_STORAGE_GET_RAIDS,
|
||||||
@ -81,7 +81,7 @@ def mock_router(mock_device_registry_devices):
|
|||||||
# home devices
|
# home devices
|
||||||
instance.home.get_home_nodes = AsyncMock(return_value=DATA_HOME_GET_NODES)
|
instance.home.get_home_nodes = AsyncMock(return_value=DATA_HOME_GET_NODES)
|
||||||
instance.home.get_home_endpoint_value = AsyncMock(
|
instance.home.get_home_endpoint_value = AsyncMock(
|
||||||
return_value=DATA_HOME_GET_VALUES
|
return_value=DATA_HOME_PIR_GET_VALUES
|
||||||
)
|
)
|
||||||
instance.close = AsyncMock()
|
instance.close = AsyncMock()
|
||||||
yield service_mock
|
yield service_mock
|
||||||
|
@ -515,7 +515,7 @@ DATA_LAN_GET_HOSTS_LIST = [
|
|||||||
|
|
||||||
# Home
|
# Home
|
||||||
# PIR node id 26, endpoint id 6
|
# PIR node id 26, endpoint id 6
|
||||||
DATA_HOME_GET_VALUES = {
|
DATA_HOME_PIR_GET_VALUES = {
|
||||||
"category": "",
|
"category": "",
|
||||||
"ep_type": "signal",
|
"ep_type": "signal",
|
||||||
"id": 6,
|
"id": 6,
|
||||||
@ -527,6 +527,15 @@ DATA_HOME_GET_VALUES = {
|
|||||||
"visibility": "normal",
|
"visibility": "normal",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Home
|
||||||
|
# ALARM node id 7, endpoint id 11
|
||||||
|
DATA_HOME_ALARM_GET_VALUES = {
|
||||||
|
"refresh": 2000,
|
||||||
|
"value": "alarm2_armed",
|
||||||
|
"value_type": "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Home
|
# Home
|
||||||
# ALL
|
# ALL
|
||||||
DATA_HOME_GET_NODES = [
|
DATA_HOME_GET_NODES = [
|
||||||
@ -2526,4 +2535,354 @@ DATA_HOME_GET_NODES = [
|
|||||||
"inherit": "node::ios",
|
"inherit": "node::ios",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"adapter": 5,
|
||||||
|
"category": "alarm",
|
||||||
|
"group": {"label": ""},
|
||||||
|
"id": 7,
|
||||||
|
"label": "Système d'alarme",
|
||||||
|
"name": "node_7",
|
||||||
|
"props": {
|
||||||
|
"Address": 3,
|
||||||
|
"Challenge": "447599f5cab8620122b913e55faf8e1d",
|
||||||
|
"FwVersion": 47396239,
|
||||||
|
"Gateway": 1,
|
||||||
|
"ItemId": "e515a55b04f32e6d",
|
||||||
|
},
|
||||||
|
"show_endpoints": [
|
||||||
|
{
|
||||||
|
"category": "",
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 5,
|
||||||
|
"label": "Code PIN",
|
||||||
|
"name": "pin",
|
||||||
|
"ui": {...},
|
||||||
|
"value": "",
|
||||||
|
"value_type": "string",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "",
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 6,
|
||||||
|
"label": "Puissance des bips",
|
||||||
|
"name": "sound",
|
||||||
|
"ui": {...},
|
||||||
|
"value": 0,
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "",
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 7,
|
||||||
|
"label": "Puissance de la sirène",
|
||||||
|
"name": "volume",
|
||||||
|
"ui": {...},
|
||||||
|
"value": 0,
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "alarm",
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 8,
|
||||||
|
"label": "Délai avant armement",
|
||||||
|
"name": "timeout1",
|
||||||
|
"ui": {...},
|
||||||
|
"value": 0,
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "alarm",
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 9,
|
||||||
|
"label": "Délai avant sirène",
|
||||||
|
"name": "timeout2",
|
||||||
|
"ui": {...},
|
||||||
|
"value": 0,
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "alarm",
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 10,
|
||||||
|
"label": "Durée de la sirène",
|
||||||
|
"name": "timeout3",
|
||||||
|
"ui": {...},
|
||||||
|
"value": 0,
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "",
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 12,
|
||||||
|
"label": "Code PIN",
|
||||||
|
"name": "pin",
|
||||||
|
"refresh": 2000,
|
||||||
|
"ui": {...},
|
||||||
|
"value": "0000",
|
||||||
|
"value_type": "string",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "",
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 14,
|
||||||
|
"label": "Puissance des bips",
|
||||||
|
"name": "sound",
|
||||||
|
"refresh": 2000,
|
||||||
|
"ui": {...},
|
||||||
|
"value": 1,
|
||||||
|
"value_type": "int",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "",
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 15,
|
||||||
|
"label": "Puissance de la sirène",
|
||||||
|
"name": "volume",
|
||||||
|
"refresh": 2000,
|
||||||
|
"ui": {...},
|
||||||
|
"value": 100,
|
||||||
|
"value_type": "int",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "alarm",
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 16,
|
||||||
|
"label": "Délai avant armement",
|
||||||
|
"name": "timeout1",
|
||||||
|
"refresh": 2000,
|
||||||
|
"ui": {...},
|
||||||
|
"value": 15,
|
||||||
|
"value_type": "int",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "alarm",
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 17,
|
||||||
|
"label": "Délai avant sirène",
|
||||||
|
"name": "timeout2",
|
||||||
|
"refresh": 2000,
|
||||||
|
"ui": {...},
|
||||||
|
"value": 15,
|
||||||
|
"value_type": "int",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "alarm",
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 18,
|
||||||
|
"label": "Durée de la sirène",
|
||||||
|
"name": "timeout3",
|
||||||
|
"refresh": 2000,
|
||||||
|
"ui": {...},
|
||||||
|
"value": 300,
|
||||||
|
"value_type": "int",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "",
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 19,
|
||||||
|
"label": "Niveau de Batterie",
|
||||||
|
"name": "battery",
|
||||||
|
"refresh": 2000,
|
||||||
|
"ui": {...},
|
||||||
|
"value": 85,
|
||||||
|
"value_type": "int",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"type": {
|
||||||
|
"abstract": False,
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 0,
|
||||||
|
"label": "Trigger",
|
||||||
|
"name": "trigger",
|
||||||
|
"value_type": "void",
|
||||||
|
"visibility": "internal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 1,
|
||||||
|
"label": "Alarme principale",
|
||||||
|
"name": "alarm1",
|
||||||
|
"value_type": "void",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 2,
|
||||||
|
"label": "Alarme secondaire",
|
||||||
|
"name": "alarm2",
|
||||||
|
"value_type": "void",
|
||||||
|
"visibility": "internal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 3,
|
||||||
|
"label": "Passer le délai",
|
||||||
|
"name": "skip",
|
||||||
|
"value_type": "void",
|
||||||
|
"visibility": "internal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 4,
|
||||||
|
"label": "Désactiver l'alarme",
|
||||||
|
"name": "off",
|
||||||
|
"value_type": "void",
|
||||||
|
"visibility": "internal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 5,
|
||||||
|
"label": "Code PIN",
|
||||||
|
"name": "pin",
|
||||||
|
"value_type": "string",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 6,
|
||||||
|
"label": "Puissance des bips",
|
||||||
|
"name": "sound",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 7,
|
||||||
|
"label": "Puissance de la sirène",
|
||||||
|
"name": "volume",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 8,
|
||||||
|
"label": "Délai avant armement",
|
||||||
|
"name": "timeout1",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 9,
|
||||||
|
"label": "Délai avant sirène",
|
||||||
|
"name": "timeout2",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "slot",
|
||||||
|
"id": 10,
|
||||||
|
"label": "Durée de la sirène",
|
||||||
|
"name": "timeout3",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 11,
|
||||||
|
"label": "État de l'alarme",
|
||||||
|
"name": "state",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "string",
|
||||||
|
"visibility": "internal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 12,
|
||||||
|
"label": "Code PIN",
|
||||||
|
"name": "pin",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "string",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 13,
|
||||||
|
"label": "Erreur",
|
||||||
|
"name": "error",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "string",
|
||||||
|
"visibility": "internal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 14,
|
||||||
|
"label": "Puissance des bips",
|
||||||
|
"name": "sound",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 15,
|
||||||
|
"label": "Puissance de la sirène",
|
||||||
|
"name": "volume",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 16,
|
||||||
|
"label": "Délai avant armement",
|
||||||
|
"name": "timeout1",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 17,
|
||||||
|
"label": "Délai avant sirène",
|
||||||
|
"name": "timeout2",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 18,
|
||||||
|
"label": "Durée de la sirène",
|
||||||
|
"name": "timeout3",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 19,
|
||||||
|
"label": "Niveau de Batterie",
|
||||||
|
"name": "battery",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ep_type": "signal",
|
||||||
|
"id": 20,
|
||||||
|
"label": "Batterie faible",
|
||||||
|
"name": "battery_warning",
|
||||||
|
"param_type": "void",
|
||||||
|
"value_type": "int",
|
||||||
|
"visibility": "normal",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"generic": False,
|
||||||
|
"icon": "/resources/images/home/pictos/alarm_system.png",
|
||||||
|
"inherit": "node::domus",
|
||||||
|
"label": "Système d'alarme",
|
||||||
|
"name": "node::domus::freebox::secmod",
|
||||||
|
"params": {},
|
||||||
|
"physical": True,
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
123
tests/components/freebox/test_alarm_control_panel.py
Normal file
123
tests/components/freebox/test_alarm_control_panel.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
"""Tests for the Freebox sensors."""
|
||||||
|
from copy import deepcopy
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.alarm_control_panel import (
|
||||||
|
DOMAIN as ALARM_CONTROL_PANEL,
|
||||||
|
AlarmControlPanelEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.components.freebox import SCAN_INTERVAL
|
||||||
|
from homeassistant.const import (
|
||||||
|
SERVICE_ALARM_ARM_AWAY,
|
||||||
|
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
|
||||||
|
SERVICE_ALARM_ARM_HOME,
|
||||||
|
SERVICE_ALARM_ARM_NIGHT,
|
||||||
|
SERVICE_ALARM_ARM_VACATION,
|
||||||
|
SERVICE_ALARM_DISARM,
|
||||||
|
SERVICE_ALARM_TRIGGER,
|
||||||
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||||
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_ARMED_VACATION,
|
||||||
|
STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_TRIGGERED,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant, State
|
||||||
|
from homeassistant.helpers.state import async_reproduce_state
|
||||||
|
|
||||||
|
from .common import setup_platform
|
||||||
|
from .const import DATA_HOME_ALARM_GET_VALUES
|
||||||
|
|
||||||
|
from tests.common import async_fire_time_changed, async_mock_service
|
||||||
|
|
||||||
|
|
||||||
|
async def test_panel(
|
||||||
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, router: Mock
|
||||||
|
) -> None:
|
||||||
|
"""Test home binary sensors."""
|
||||||
|
await setup_platform(hass, ALARM_CONTROL_PANEL)
|
||||||
|
|
||||||
|
# Initial state
|
||||||
|
assert hass.states.get("alarm_control_panel.systeme_d_alarme").state == "unknown"
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.systeme_d_alarme").attributes[
|
||||||
|
"supported_features"
|
||||||
|
]
|
||||||
|
== AlarmControlPanelEntityFeature.ARM_AWAY
|
||||||
|
)
|
||||||
|
|
||||||
|
# Now simulate a changed status
|
||||||
|
data_get_home_endpoint_value = deepcopy(DATA_HOME_ALARM_GET_VALUES)
|
||||||
|
router().home.get_home_endpoint_value.return_value = data_get_home_endpoint_value
|
||||||
|
|
||||||
|
# Simulate an update
|
||||||
|
freezer.tick(SCAN_INTERVAL)
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.systeme_d_alarme").state == "armed_night"
|
||||||
|
)
|
||||||
|
# Fake that the entity is triggered.
|
||||||
|
hass.states.async_set("alarm_control_panel.systeme_d_alarme", STATE_ALARM_DISARMED)
|
||||||
|
assert hass.states.get("alarm_control_panel.systeme_d_alarme").state == "disarmed"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reproducing_states(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test reproducing Alarm control panel states."""
|
||||||
|
hass.states.async_set(
|
||||||
|
"alarm_control_panel.entity_armed_away", STATE_ALARM_ARMED_AWAY, {}
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"alarm_control_panel.entity_armed_custom_bypass",
|
||||||
|
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"alarm_control_panel.entity_armed_home", STATE_ALARM_ARMED_HOME, {}
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"alarm_control_panel.entity_armed_night", STATE_ALARM_ARMED_NIGHT, {}
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"alarm_control_panel.entity_armed_vacation", STATE_ALARM_ARMED_VACATION, {}
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"alarm_control_panel.entity_disarmed", STATE_ALARM_DISARMED, {}
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"alarm_control_panel.entity_triggered", STATE_ALARM_TRIGGERED, {}
|
||||||
|
)
|
||||||
|
|
||||||
|
async_mock_service(hass, "alarm_control_panel", SERVICE_ALARM_ARM_AWAY)
|
||||||
|
async_mock_service(hass, "alarm_control_panel", SERVICE_ALARM_ARM_CUSTOM_BYPASS)
|
||||||
|
async_mock_service(hass, "alarm_control_panel", SERVICE_ALARM_ARM_HOME)
|
||||||
|
async_mock_service(hass, "alarm_control_panel", SERVICE_ALARM_ARM_NIGHT)
|
||||||
|
async_mock_service(hass, "alarm_control_panel", SERVICE_ALARM_ARM_VACATION)
|
||||||
|
async_mock_service(hass, "alarm_control_panel", SERVICE_ALARM_DISARM)
|
||||||
|
async_mock_service(hass, "alarm_control_panel", SERVICE_ALARM_TRIGGER)
|
||||||
|
|
||||||
|
# These calls should do nothing as entities already in desired state
|
||||||
|
await async_reproduce_state(
|
||||||
|
hass,
|
||||||
|
[
|
||||||
|
State("alarm_control_panel.entity_armed_away", STATE_ALARM_ARMED_AWAY),
|
||||||
|
State(
|
||||||
|
"alarm_control_panel.entity_armed_custom_bypass",
|
||||||
|
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
||||||
|
),
|
||||||
|
State("alarm_control_panel.entity_armed_home", STATE_ALARM_ARMED_HOME),
|
||||||
|
State("alarm_control_panel.entity_armed_night", STATE_ALARM_ARMED_NIGHT),
|
||||||
|
State(
|
||||||
|
"alarm_control_panel.entity_armed_vacation", STATE_ALARM_ARMED_VACATION
|
||||||
|
),
|
||||||
|
State("alarm_control_panel.entity_disarmed", STATE_ALARM_DISARMED),
|
||||||
|
State("alarm_control_panel.entity_triggered", STATE_ALARM_TRIGGERED),
|
||||||
|
],
|
||||||
|
)
|
@ -13,7 +13,7 @@ from homeassistant.const import ATTR_DEVICE_CLASS
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import setup_platform
|
from .common import setup_platform
|
||||||
from .const import DATA_HOME_GET_VALUES, DATA_STORAGE_GET_RAIDS
|
from .const import DATA_HOME_PIR_GET_VALUES, DATA_STORAGE_GET_RAIDS
|
||||||
|
|
||||||
from tests.common import async_fire_time_changed
|
from tests.common import async_fire_time_changed
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ async def test_home(
|
|||||||
assert hass.states.get("binary_sensor.ouverture_porte_couvercle").state == "off"
|
assert hass.states.get("binary_sensor.ouverture_porte_couvercle").state == "off"
|
||||||
|
|
||||||
# Now simulate a changed status
|
# Now simulate a changed status
|
||||||
data_home_get_values_changed = deepcopy(DATA_HOME_GET_VALUES)
|
data_home_get_values_changed = deepcopy(DATA_HOME_PIR_GET_VALUES)
|
||||||
data_home_get_values_changed["value"] = True
|
data_home_get_values_changed["value"] = True
|
||||||
router().home.get_home_endpoint_value.return_value = data_home_get_values_changed
|
router().home.get_home_endpoint_value.return_value = data_home_get_values_changed
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user