Skip to content

Commit

Permalink
refactor: options config flow
Browse files Browse the repository at this point in the history
  • Loading branch information
xtimmy86x committed Nov 1, 2023
1 parent eb156d0 commit 185a165
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 63 deletions.
27 changes: 16 additions & 11 deletions custom_components/econnect_metronet/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""Config flow for E-connect Alarm integration."""
import logging

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from elmo import query as q
from elmo.api.exceptions import CredentialError
from elmo.systems import ELMO_E_CONNECT as E_CONNECT_DEFAULT
from homeassistant import config_entries
Expand All @@ -18,6 +20,7 @@
CONF_SYSTEM_NAME,
CONF_SYSTEM_URL,
DOMAIN,
KEY_DEVICE,
SUPPORTED_SYSTEMS,
)
from .exceptions import InvalidAreas
Expand Down Expand Up @@ -127,28 +130,30 @@ async def async_step_init(self, user_input=None):

# Populate with latest changes or previous settings
user_input = user_input or {}
suggest_arm_home = user_input.get(CONF_AREAS_ARM_HOME) or self.config_entry.options.get(CONF_AREAS_ARM_HOME)
suggest_arm_night = user_input.get(CONF_AREAS_ARM_NIGHT) or self.config_entry.options.get(CONF_AREAS_ARM_NIGHT)
suggest_arm_vacation = user_input.get(CONF_AREAS_ARM_VACATION) or self.config_entry.options.get(
CONF_AREAS_ARM_VACATION
)
suggest_scan_interval = user_input.get(CONF_SCAN_INTERVAL) or self.config_entry.options.get(CONF_SCAN_INTERVAL)

# Generate sectors list for user config options
sectors_list = []
device = self.hass.data[DOMAIN][self.config_entry.entry_id][KEY_DEVICE]
for sector_id, item in device._inventory.get(q.SECTORS, {}).items():
sectors_list.append(f"{item['element']} : {item['name']}")

return self.async_show_form(
step_id="init",
data_schema=vol.Schema(
{
vol.Optional(
CONF_AREAS_ARM_HOME,
description={"suggested_value": suggest_arm_home},
): str,
default=self.config_entry.options.get(CONF_AREAS_ARM_HOME),
): cv.multi_select(sectors_list),
vol.Optional(
CONF_AREAS_ARM_NIGHT,
description={"suggested_value": suggest_arm_night},
): str,
default=self.config_entry.options.get(CONF_AREAS_ARM_NIGHT),
): cv.multi_select(sectors_list),
vol.Optional(
CONF_AREAS_ARM_VACATION,
description={"suggested_value": suggest_arm_vacation},
): str,
default=self.config_entry.options.get(CONF_AREAS_ARM_VACATION),
): cv.multi_select(sectors_list),
vol.Optional(
CONF_SCAN_INTERVAL,
description={"suggested_value": suggest_scan_interval},
Expand Down
48 changes: 22 additions & 26 deletions custom_components/econnect_metronet/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,38 @@


def parse_areas_config(config: str, raises: bool = False):
"""Parses a comma-separated string of area configurations into a list of integers.
"""Extracts sector numbers from the provided configuration.
Takes a string containing comma-separated area IDs and converts it to a list of integers.
In case of any parsing errors, either raises a custom `InvalidAreas` exception or returns an empty list
based on the `raises` flag.
Args:
config (str): A comma-separated string of area IDs, e.g., "3,4".
raises (bool, optional): Determines the error handling behavior. If `True`, the function
raises the `InvalidAreas` exception upon encountering a parsing error.
If `False`, it suppresses the error and returns an empty list.
Defaults to `False`.
Parameters:
config (str or None): A string containing sector configurations in the format "number:name".
If empty or None, an empty list is returned.
raises (bool, optional): If True, raises an InvalidAreas exception if there's an error in parsing.
Defaults to True.
Returns:
list[int]: A list of integers representing area IDs. If parsing fails and `raises` is `False`,
returns an empty list.
list: A list of integers representing the extracted sector numbers.
Raises:
InvalidAreas: If there's a parsing error and the `raises` flag is set to `True`.
InvalidAreas: If raises is set to True and there is an error in parsing.
Examples:
>>> parse_areas_config("3,4")
[3, 4]
>>> parse_areas_config("3,a")
[]
Example:
>>> config = "1:sector1 2:sector2 3:sector3"
>>> parse_areas_config(config)
[1, 2, 3]
"""
if config == "" or config is None:
# Empty config is considered valid (no sectors configured)
return []

try:
return [int(x) for x in config.split(",")]
except (ValueError, AttributeError):
if raises:
raise InvalidAreas
return []
result = []
for item in config:
try:
number = int(item.split(":")[0])
result.append(number)
except (ValueError, AttributeError):
if raises:
raise InvalidAreas
return []
return result


async def validate_credentials(hass: core.HomeAssistant, config: dict):
Expand Down
10 changes: 5 additions & 5 deletions custom_components/econnect_metronet/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
"step": {
"init": {
"data": {
"areas_arm_home": "Armed areas while at home (e.g 3,4 - optional)",
"areas_arm_night": "Armed areas at night (e.g. 3,4 - optional)",
"areas_arm_vacation": "Armed areas when you are on vacation (e.g. 3,4 - optional)",
"areas_arm_home": "Armed areas while at home (optional)",
"areas_arm_night": "Armed areas at night (optional)",
"areas_arm_vacation": "Armed areas when you are on vacation (optional)",
"scan_interval": "Scan interval (e.g. 120 - optional)"
},
"description": "Define sectors you want to arm in different modes.\n\nSet 'Scan Interval' value only if you want to reduce data usage, in case the system is connected through a mobile network. Leave it empty for real time updates, or set it to a value in seconds (e.g. 120 for one update every 2 minutes)",
"title": "Configure your Elmo/IESS system"
"description": "Choose from the proposed sectors the ones you wish to equip in different modes.\n\nSet 'Scan Interval' value only if you want to reduce data usage, in case the system is connected through a mobile network. Leave it empty for real time updates, or set it to a value in seconds (e.g. 120 for one update every 2 minutes)",
"title": "Configure your eConnect/Metronet system"
}
}
},
Expand Down
10 changes: 5 additions & 5 deletions custom_components/econnect_metronet/translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
"step": {
"init": {
"data": {
"areas_arm_home": "Settori armati mentre sei a casa (es. 3,4 - opzionale)",
"areas_arm_night": "Settori armati di notte (es. 3,4 - opzionale)",
"areas_arm_vacation": "Settori armati quando sei in vacanza (es. 3,4 - opzionale)",
"areas_arm_home": "Settori armati mentre sei a casa (opzionale)",
"areas_arm_night": "Settori armati di notte (opzionale)",
"areas_arm_vacation": "Settori armati quando sei in vacanza (opzionale)",
"scan_interval": "Intervallo di scansione (es. 120 - opzionale)"
},
"description": "Definisci i settori che desideri armare in diverse modalità.\n\nImposta il valore 'Intervallo di scansione' solo se desideri ridurre l'utilizzo dei dati, nel caso in cui il sistema sia connesso tramite una rete mobile (SIM). Lascialo vuoto per aggiornamenti in tempo reale, oppure imposta un valore in secondi (es. 120 per un aggiornamento ogni 2 minuti)",
"title": "Configura il tuo sistema Elmo/IESS"
"description": "Scegli tra quelli proposti i settori che desideri armare nelle diverse modalità.\n\nImposta il valore 'Intervallo di scansione' solo se desideri ridurre l'utilizzo dei dati, nel caso in cui il sistema sia connesso tramite una rete mobile (SIM). Lascialo vuoto per aggiornamenti in tempo reale, oppure imposta un valore in secondi (es. 120 per un aggiornamento ogni 2 minuti)",
"title": "Configura il tuo sistema eConnect/Metronet"
}
}
},
Expand Down
6 changes: 3 additions & 3 deletions tests/test_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ def test_device_constructor(client):
def test_device_constructor_with_config(client):
"""Should initialize defaults attributes to run properly."""
config = {
CONF_AREAS_ARM_HOME: "3, 4",
CONF_AREAS_ARM_NIGHT: "1, 2, 3",
CONF_AREAS_ARM_VACATION: "5, 3",
CONF_AREAS_ARM_HOME: ("3 : Garage\nCler", "4 : Garage\nRadar"),
CONF_AREAS_ARM_NIGHT: ("1 : Garage\nCler", "2 : Garage\nRadar", "3 : Garage\nCler"),
CONF_AREAS_ARM_VACATION: ("5 : Garage\nCler", "3 : Garage\nRadar"),
}
device = AlarmDevice(client, config=config)
# Test
Expand Down
17 changes: 4 additions & 13 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@


def test_parse_areas_config_valid_input():
assert parse_areas_config("3,4") == [3, 4]
assert parse_areas_config("1,2,3,4,5") == [1, 2, 3, 4, 5]
assert parse_areas_config("10") == [10]
input = ("4 : Garage\nCler", "5 : Garage\nRadar")
input2 = ("2 : Casa\nFinestre", "3 : Casa\nRadar", "4 : Garage\nCler", "5 : Garage\nRadar")
assert parse_areas_config(input) == [4, 5]
assert parse_areas_config(input2) == [2, 3, 4, 5]
assert parse_areas_config("") == []


Expand All @@ -20,23 +21,13 @@ def test_parse_areas_config_valid_empty_input():
assert parse_areas_config(None, raises=True) == []


def test_parse_areas_config_invalid_input():
assert parse_areas_config("3,a") == []
assert parse_areas_config("3.4") == []
assert parse_areas_config("3,") == []


def test_parse_areas_config_raises_value_error():
with pytest.raises(InvalidAreas):
parse_areas_config("3,a", raises=True)
with pytest.raises(InvalidAreas):
parse_areas_config("3.4", raises=True)


def test_parse_areas_config_whitespace():
assert parse_areas_config(" 3 , 4 ") == [3, 4]


def test_generate_entity_name_empty(config_entry):
entity_id = generate_entity_id(config_entry)
assert entity_id == "econnect_metronet.econnect_metronet_test_user"
Expand Down

0 comments on commit 185a165

Please sign in to comment.