diff --git a/custom_components/elmo_iess_alarm/alarm_control_panel.py b/custom_components/elmo_iess_alarm/alarm_control_panel.py index 6714dfe..703a687 100644 --- a/custom_components/elmo_iess_alarm/alarm_control_panel.py +++ b/custom_components/elmo_iess_alarm/alarm_control_panel.py @@ -26,6 +26,7 @@ from .const import DOMAIN, KEY_COORDINATOR, KEY_DEVICE from .decorators import set_device_state +from .helpers import generate_entity_name _LOGGER = logging.getLogger(__name__) @@ -38,7 +39,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_d async_add_devices( [ EconnectAlarm( - "Alarm Panel", + generate_entity_name(entry), device, coordinator, unique_id, diff --git a/custom_components/elmo_iess_alarm/binary_sensor.py b/custom_components/elmo_iess_alarm/binary_sensor.py index e2ce5dd..a0dcd5b 100644 --- a/custom_components/elmo_iess_alarm/binary_sensor.py +++ b/custom_components/elmo_iess_alarm/binary_sensor.py @@ -12,6 +12,7 @@ from custom_components.elmo_iess_alarm.devices import AlarmDevice from .const import DOMAIN, KEY_COORDINATOR, KEY_DEVICE +from .helpers import generate_entity_name async def async_setup_entry( @@ -29,11 +30,19 @@ async def async_setup_entry( inventory = await hass.async_add_executor_job(device._connection._get_descriptions) for sector_id, name in inventory[query.SECTORS].items(): unique_id = f"{entry.entry_id}_{DOMAIN}_{query.SECTORS}_{sector_id}" - sensors.append(EconnectDoorWindowSensor(coordinator, device, unique_id, sector_id, query.SECTORS, name)) + sensors.append( + EconnectDoorWindowSensor( + coordinator, device, unique_id, sector_id, query.SECTORS, generate_entity_name(entry, name) + ) + ) for sensor_id, name in inventory[query.INPUTS].items(): unique_id = f"{entry.entry_id}_{DOMAIN}_{query.INPUTS}_{sensor_id}" - sensors.append(EconnectDoorWindowSensor(coordinator, device, unique_id, sensor_id, query.INPUTS, name)) + sensors.append( + EconnectDoorWindowSensor( + coordinator, device, unique_id, sensor_id, query.INPUTS, generate_entity_name(entry, name) + ) + ) async_add_entities(sensors) @@ -56,7 +65,7 @@ def __init__( self._unique_id = unique_id self._sensor_id = sensor_id self._sensor_type = sensor_type - self._name = f"{DOMAIN} {name}" + self._name = name @property def unique_id(self) -> str: diff --git a/custom_components/elmo_iess_alarm/config_flow.py b/custom_components/elmo_iess_alarm/config_flow.py index b0e25b3..2cff929 100644 --- a/custom_components/elmo_iess_alarm/config_flow.py +++ b/custom_components/elmo_iess_alarm/config_flow.py @@ -14,6 +14,7 @@ CONF_AREAS_ARM_NIGHT, CONF_AREAS_ARM_VACATION, CONF_DOMAIN, + CONF_SYSTEM_NAME, CONF_SYSTEM_URL, DOMAIN, SUPPORTED_SYSTEMS, @@ -84,6 +85,10 @@ async def async_step_user(self, user_input=None): CONF_DOMAIN, description={"suggested_value": user_input.get(CONF_DOMAIN)}, ): str, + vol.Optional( + CONF_SYSTEM_NAME, + description={"suggested_value": user_input.get(CONF_SYSTEM_NAME)}, + ): str, } ), errors=errors, diff --git a/custom_components/elmo_iess_alarm/const.py b/custom_components/elmo_iess_alarm/const.py index b727878..3b508ba 100644 --- a/custom_components/elmo_iess_alarm/const.py +++ b/custom_components/elmo_iess_alarm/const.py @@ -7,6 +7,7 @@ } CONF_DOMAIN = "domain" CONF_SYSTEM_URL = "system_base_url" +CONF_SYSTEM_NAME = "system_name" CONF_AREAS_ARM_HOME = "areas_arm_home" CONF_AREAS_ARM_NIGHT = "areas_arm_night" CONF_AREAS_ARM_VACATION = "areas_arm_vacation" diff --git a/custom_components/elmo_iess_alarm/helpers.py b/custom_components/elmo_iess_alarm/helpers.py index 37fe6a6..a1cb5db 100644 --- a/custom_components/elmo_iess_alarm/helpers.py +++ b/custom_components/elmo_iess_alarm/helpers.py @@ -1,9 +1,12 @@ """Helper methods to reuse common logic across elmo_iess_alarm module.""" +from typing import Union + from elmo.api.client import ElmoClient from homeassistant import core +from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from .const import CONF_DOMAIN, CONF_SYSTEM_URL +from .const import CONF_DOMAIN, CONF_SYSTEM_NAME, CONF_SYSTEM_URL, DOMAIN from .exceptions import InvalidAreas @@ -67,3 +70,26 @@ async def validate_credentials(hass: core.HomeAssistant, config: dict): client = ElmoClient(config.get(CONF_SYSTEM_URL), domain=config.get(CONF_DOMAIN)) await hass.async_add_executor_job(client.auth, config.get(CONF_USERNAME), config.get(CONF_PASSWORD)) return True + + +def generate_entity_name(entry: ConfigEntry, name: Union[str, None] = None) -> str: + """Generate a name for the entity based on system configuration or username. + + Args: + entry (ConfigEntry): The configuration entry from Home Assistant containing system + configuration or username. + + Returns: + str: The generated entity name, which is a combination of the domain and either the configured + system name or the username. + + Example: + >>> entry.data = {"system_name": "Seaside Home"} + >>> generate_entity_name(entry, "window") + "elmo_iess_alarm_seaside_home_window" + """ + if CONF_SYSTEM_NAME in entry.data: + entity_system_name = f"{DOMAIN} {entry.data[CONF_SYSTEM_NAME]} {name or ''}".strip() + else: + entity_system_name = f"{DOMAIN} {entry.data[CONF_USERNAME]} {name or ''}".strip() + return entity_system_name diff --git a/custom_components/elmo_iess_alarm/manifest.json b/custom_components/elmo_iess_alarm/manifest.json index 487a48d..050f65e 100644 --- a/custom_components/elmo_iess_alarm/manifest.json +++ b/custom_components/elmo_iess_alarm/manifest.json @@ -18,4 +18,4 @@ "econnect-python==0.6.0" ], "version": "1.0.0" -} \ No newline at end of file +} diff --git a/custom_components/elmo_iess_alarm/strings.json b/custom_components/elmo_iess_alarm/strings.json index f0ab802..15990ca 100644 --- a/custom_components/elmo_iess_alarm/strings.json +++ b/custom_components/elmo_iess_alarm/strings.json @@ -5,7 +5,8 @@ "data": { "domain": "Domain name (optional)", "username": "[%key:common::config_flow::data::username%]", - "password": "[%key:common::config_flow::data::password%]" + "password": "[%key:common::config_flow::data::password%]", + "system_name": "[%key:common::config_flow::data::system_name%]" }, "description": "Provide your credentials and the domain used to access your login page via web.\n\nFor instance, if you access to `https://connect.elmospa.com/vendor/`, you must set the domain to `vendor`. In case you don't have a vendor defined, set it to `default`.\n\nYou can configure the system selecting \"Options\" after installing the integration.", "title": "Configure your Elmo/IESS system" diff --git a/custom_components/elmo_iess_alarm/translations/en.json b/custom_components/elmo_iess_alarm/translations/en.json index cd59d18..c0dc23a 100644 --- a/custom_components/elmo_iess_alarm/translations/en.json +++ b/custom_components/elmo_iess_alarm/translations/en.json @@ -14,7 +14,8 @@ "data": { "domain": "Domain name (optional)", "username": "Username", - "password": "Password" + "password": "Password", + "system_name": "Name of the control panel (optional)" }, "description": "Provide your credentials and the domain used to access your login page via web.\n\nFor instance, if you access to `https://connect.elmospa.com/vendor/`, you must set the domain to `vendor`. In case you don't have a vendor defined, set it to `default`.\n\nYou can configure the system selecting \"Options\" after installing the integration.", "title": "Configure your Elmo/IESS system" diff --git a/custom_components/elmo_iess_alarm/translations/it.json b/custom_components/elmo_iess_alarm/translations/it.json index b42371a..48735dd 100644 --- a/custom_components/elmo_iess_alarm/translations/it.json +++ b/custom_components/elmo_iess_alarm/translations/it.json @@ -14,7 +14,8 @@ "data": { "domain": "Nome dominio (opzionale)", "username": "Nome utente", - "password": "Password" + "password": "Password", + "system_name": "Nome dell'impianto (opzionale)" }, "description": "Fornisci le tue credenziali e il dominio utilizzato per accedere alla tua pagina di login via web.\n\nAd esempio, se accedi a `https://connect.elmospa.com/installatore/`, devi impostare il dominio su `installatore`. Nel caso in cui non hai un installatore definito, impostalo su `default`.\n\nPuoi configurare il sistema selezionando \"Opzioni\" dopo aver installato l'integrazione.", "title": "Configura il tuo sistema Elmo/IESS" diff --git a/tests/conftest.py b/tests/conftest.py index f984ff8..d00a863 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -68,3 +68,20 @@ def client(): server.add(responses.POST, "https://example.com/api/areas", body=r.AREAS, status=200) server.add(responses.POST, "https://example.com/api/inputs", body=r.INPUTS, status=200) yield client + + +@pytest.fixture(scope="function") +def config_entry(): + """Creates a mock config entry for testing purposes. + + This config entry is designed to emulate the behavior of a real config entry for + testing purposes. + """ + + class MockConfigEntry: + def __init__(self): + self.data = { + "username": "test_user", + } + + return MockConfigEntry() diff --git a/tests/test_helpers.py b/tests/test_helpers.py index a6ec060..2c0fd03 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -1,7 +1,10 @@ import pytest from custom_components.elmo_iess_alarm.exceptions import InvalidAreas -from custom_components.elmo_iess_alarm.helpers import parse_areas_config +from custom_components.elmo_iess_alarm.helpers import ( + generate_entity_name, + parse_areas_config, +) def test_parse_areas_config_valid_input(): @@ -31,3 +34,30 @@ def test_parse_areas_config_raises_value_error(): def test_parse_areas_config_whitespace(): assert parse_areas_config(" 3 , 4 ") == [3, 4] + + +def test_generate_entity_name_empty(config_entry): + assert generate_entity_name(config_entry) == "elmo_iess_alarm test_user" + + +def test_generate_entity_name_with_name(config_entry): + assert generate_entity_name(config_entry, "window") == "elmo_iess_alarm test_user window" + + +def test_generate_entity_name_with_none(config_entry): + assert generate_entity_name(config_entry, None) == "elmo_iess_alarm test_user" + + +def test_generate_entity_name_empty_system(config_entry): + config_entry.data["system_name"] = "Home" + assert generate_entity_name(config_entry) == "elmo_iess_alarm Home" + + +def test_generate_entity_name_with_name_system(config_entry): + config_entry.data["system_name"] = "Home" + assert generate_entity_name(config_entry, "window") == "elmo_iess_alarm Home window" + + +def test_generate_entity_name_with_none_system(config_entry): + config_entry.data["system_name"] = "Home" + assert generate_entity_name(config_entry, None) == "elmo_iess_alarm Home"