From bae652bee341ff1997aae37a928e2d92d1077159 Mon Sep 17 00:00:00 2001 From: Emanuele Palazzetti Date: Fri, 1 Mar 2024 14:15:50 +0000 Subject: [PATCH] feat(entity): add connection status binary sensor to provide feedback in case of a disconnection --- .../econnect_metronet/binary_sensor.py | 4 ++++ .../econnect_metronet/devices.py | 5 +++++ .../econnect_metronet/strings.json | 7 ++++++ .../econnect_metronet/translations/en.json | 7 ++++++ .../econnect_metronet/translations/it.json | 7 ++++++ tests/test_binary_sensors.py | 22 ++++++++++++++++++- 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/custom_components/econnect_metronet/binary_sensor.py b/custom_components/econnect_metronet/binary_sensor.py index 4eefc48..84f327d 100644 --- a/custom_components/econnect_metronet/binary_sensor.py +++ b/custom_components/econnect_metronet/binary_sensor.py @@ -54,6 +54,10 @@ async def async_setup_entry( unique_id = f"{entry.entry_id}_{DOMAIN}_{name}" sensors.append(AlertBinarySensor(unique_id, alert_id, entry, name, coordinator, device)) + # Binary sensor to keep track of the device connection status + unique_id = f"{entry.entry_id}_{DOMAIN}_connection_status" + sensors.append(AlertBinarySensor(unique_id, -1, entry, "connection_status", coordinator, device)) + async_add_entities(sensors) diff --git a/custom_components/econnect_metronet/devices.py b/custom_components/econnect_metronet/devices.py index caa2a4f..88064ef 100644 --- a/custom_components/econnect_metronet/devices.py +++ b/custom_components/econnect_metronet/devices.py @@ -251,6 +251,11 @@ def get_status(self, query: int, id: int) -> Union[bool, int]: Returns: int: The status of the item. """ + if query == q.ALERTS and id == -1: + # Connection Status Alert + # NOTE: we should turn on the sensor (alert) if the device is not connected, hence the `not` + return not self.connected + return self._inventory[query][id]["status"] def update(self): diff --git a/custom_components/econnect_metronet/strings.json b/custom_components/econnect_metronet/strings.json index 19502a4..e5423cb 100644 --- a/custom_components/econnect_metronet/strings.json +++ b/custom_components/econnect_metronet/strings.json @@ -43,6 +43,13 @@ }, "entity": { "binary_sensor": { + "connection_status": { + "name": "Connection Status", + "state": { + "on": "Disconnected", + "off": "Connected" + } + }, "anomalies_led": { "name": "General Anomaly", "state": { diff --git a/custom_components/econnect_metronet/translations/en.json b/custom_components/econnect_metronet/translations/en.json index e78cc81..7f2aa26 100644 --- a/custom_components/econnect_metronet/translations/en.json +++ b/custom_components/econnect_metronet/translations/en.json @@ -69,6 +69,13 @@ } }, "binary_sensor": { + "connection_status": { + "name": "Connection Status", + "state": { + "on": "Disconnected", + "off": "Connected" + } + }, "anomalies_led": { "name": "General Anomaly", "state": { diff --git a/custom_components/econnect_metronet/translations/it.json b/custom_components/econnect_metronet/translations/it.json index bab6147..4e118c3 100644 --- a/custom_components/econnect_metronet/translations/it.json +++ b/custom_components/econnect_metronet/translations/it.json @@ -69,6 +69,13 @@ } }, "binary_sensor": { + "connection_status": { + "name": "Stato Connessione", + "state": { + "on": "Disconnessa", + "off": "Connessa" + } + }, "anomalies_led": { "name": "Anomalia Generale", "state": { diff --git a/tests/test_binary_sensors.py b/tests/test_binary_sensors.py index 8a9ad6a..b412e80 100644 --- a/tests/test_binary_sensors.py +++ b/tests/test_binary_sensors.py @@ -22,11 +22,31 @@ async def test_async_setup_entry_in_use(hass, config_entry, alarm_device, coordi # Test def ensure_only_in_use(sensors): - assert len(sensors) == 28 + assert len(sensors) == 29 await async_setup_entry(hass, config_entry, ensure_only_in_use) +@pytest.mark.asyncio +async def test_async_setup_entry_connection_status(hass, config_entry, alarm_device, coordinator): + # Ensure the async setup loads the device connection status + hass.data[DOMAIN][config_entry.entry_id] = { + "device": alarm_device, + "coordinator": coordinator, + } + + # Test + def check_connection_status(sensors): + connection_status = sensors[-1] + assert connection_status.unique_id == "test_entry_id_econnect_metronet_connection_status" + assert connection_status.entity_id == "econnect_metronet.econnect_metronet_test_user_connection_status" + assert connection_status.is_on is False + alarm_device.connected = False + assert connection_status.is_on is True + + await async_setup_entry(hass, config_entry, check_connection_status) + + @pytest.mark.asyncio async def test_async_setup_entry_unused_input(hass, config_entry, alarm_device, coordinator): # Ensure the async setup don't load inputs that are not in use