|
1 | | -"""Config flow.""" |
| 1 | +""" config_flow.py """ |
2 | 2 |
|
3 | | -import asyncio |
4 | 3 | import logging |
5 | | - |
6 | 4 | import voluptuous as vol |
7 | 5 |
|
8 | | -from homeassistant import config_entries |
9 | 6 | from homeassistant.core import callback |
| 7 | +from homeassistant import config_entries |
10 | 8 |
|
11 | 9 | from .const import DOMAIN, KEYS |
| 10 | +from .ecu_api import APsystemsSocket, APsystemsInvalidData |
12 | 11 |
|
13 | 12 | _LOGGER = logging.getLogger(__name__) |
14 | 13 |
|
| 14 | +STEP_USER_DATA_SCHEMA = vol.Schema({ |
| 15 | + vol.Required(KEYS[0], default= ''): str, |
| 16 | + vol.Required(KEYS[1], default= 300): int, |
| 17 | + vol.Optional(KEYS[2], default= 5): int, # Port retries |
| 18 | + vol.Optional(KEYS[3], default= "ECU-WIFI_local"): str, |
| 19 | + vol.Optional(KEYS[4], default= "default"): str, |
| 20 | + vol.Optional(KEYS[5], default= False): bool, |
| 21 | +}) |
15 | 22 |
|
16 | | -async def validate_ip(ip_address: str) -> bool: |
17 | | - """Validate EMA server ip.""" |
18 | | - try: |
19 | | - reader, writer = await asyncio.wait_for( |
20 | | - asyncio.open_connection(ip_address, 8995), timeout=3.0 |
21 | | - ) |
22 | | - # Close the connection neatly |
23 | | - writer.close() |
24 | | - await writer.wait_closed() |
25 | | - except (OSError, TimeoutError): |
26 | | - return False |
27 | | - else: |
28 | | - return True |
29 | | - |
30 | | - |
31 | | -class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): |
32 | | - """Integration configuration.""" |
| 23 | +@config_entries.HANDLERS.register(DOMAIN) |
| 24 | +class FlowHandler(config_entries.ConfigFlow): |
33 | 25 |
|
34 | 26 | VERSION = 1 |
35 | | - CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH |
36 | | - |
37 | | - @staticmethod |
38 | | - @callback |
39 | | - def async_get_options_flow(config_entry): |
40 | | - """Get stored configuration data to present in async_step_init.""" |
41 | | - _LOGGER.debug("async_get_options_flow called: %s", config_entry) |
42 | | - return OptionsFlowHandler(config_entry) |
43 | 27 |
|
44 | 28 | async def async_step_user(self, user_input=None): |
45 | | - """First step: Initial set-up of integration options.""" |
46 | | - _LOGGER.debug("async_step_user") |
47 | | - schema = vol.Schema( |
48 | | - { |
49 | | - vol.Required(KEYS[0], default="3.67.1.32"): str, |
50 | | - vol.Required(KEYS[1], default="1800"): str, |
51 | | - vol.Required(KEYS[2], default="300"): str, |
52 | | - vol.Required(KEYS[3], default="660"): str, |
53 | | - vol.Required(KEYS[4], default=True): bool, |
54 | | - } |
55 | | - ) |
56 | | - |
57 | | - if user_input is not None: |
58 | | - if await validate_ip(user_input["ema_host"]): |
59 | | - return self.async_create_entry( |
60 | | - title="APsystems ECU proxy", data=user_input |
61 | | - ) |
| 29 | + errors = {} |
| 30 | + if user_input is None: |
| 31 | + # Show form because user input is empty. |
| 32 | + return self.async_show_form( |
| 33 | + step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors |
| 34 | + ) |
62 | 35 |
|
| 36 | + # User input is not empty, processing input. |
| 37 | + retries = user_input.get(KEYS[2], 5) # Get port_retries from user input, default to 5 |
| 38 | + show_graphs = user_input.get(KEYS[5], False) # Get show_graphs from user input, default to False |
| 39 | + _LOGGER.warning("1. show_graphs = %s", show_graphs) |
| 40 | + ecu_id = await test_ecu_connection(self.hass, user_input["ecu_host"], retries, show_graphs) |
| 41 | + _LOGGER.debug("ecu_id = %s", ecu_id) |
| 42 | + |
| 43 | + if ecu_id: |
| 44 | + return self.async_create_entry(title=f"ECU: {ecu_id}", data=user_input) |
| 45 | + else: |
| 46 | + errors["ecu_host"] = "no_ecu_found" |
63 | 47 | return self.async_show_form( |
64 | | - step_id="user", |
65 | | - data_schema=schema, |
66 | | - errors={"base": "Could not connect to the specified EMA host"}, |
| 48 | + step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors |
67 | 49 | ) |
68 | | - return self.async_show_form(step_id="user", data_schema=schema) |
69 | 50 |
|
| 51 | + # Enable the integration to be reconfigured in the UI |
| 52 | + @staticmethod |
| 53 | + @callback |
| 54 | + def async_get_options_flow(config_entry): |
| 55 | + return OptionsFlowHandler() |
70 | 56 |
|
71 | 57 | class OptionsFlowHandler(config_entries.OptionsFlow): |
72 | | - """Regular change of integration options.""" |
| 58 | + """Regular change of integration configuration.""" |
73 | 59 |
|
74 | | - def __init__(self, config_entry: config_entries.ConfigEntry) -> None: |
75 | | - """Init options handler.""" |
76 | | - self.config_entry = config_entry |
| 60 | + #def __init__(self, config_entry: config_entries.ConfigEntry) -> None: |
| 61 | + def __init__(self) -> None: |
| 62 | + """Init options flow.""" |
| 63 | + # self.config_entry = config_entry |
77 | 64 |
|
78 | 65 | async def async_step_init(self, user_input=None): |
79 | | - """Second step: Altering the integration options.""" |
| 66 | + """Altering the integration configuration.""" |
80 | 67 | errors = {} |
81 | 68 | current_options = ( |
82 | 69 | self.config_entry.data |
83 | 70 | if not self.config_entry.options |
84 | 71 | else self.config_entry.options |
85 | 72 | ) |
| 73 | + |
86 | 74 | _LOGGER.debug("async_step_init with configuration: %s", current_options) |
87 | 75 |
|
88 | 76 | schema = vol.Schema( |
89 | 77 | { |
90 | | - vol.Required(key, default=current_options.get(key)): ( |
91 | | - str if key != "send_to_ema" else bool |
92 | | - ) |
93 | | - for key in KEYS |
| 78 | + vol.Required(KEYS[0], default=current_options.get(KEYS[0])): str, |
| 79 | + vol.Required(KEYS[1], default=current_options.get(KEYS[1])): int, |
| 80 | + vol.Optional(KEYS[2], default=current_options.get(KEYS[2])): int, # Port retries |
| 81 | + vol.Optional(KEYS[3], default=current_options.get(KEYS[3])): str, |
| 82 | + vol.Optional(KEYS[4], default=current_options.get(KEYS[4])): str, |
| 83 | + vol.Optional(KEYS[5], default=current_options.get(KEYS[5])): bool, |
94 | 84 | } |
95 | 85 | ) |
96 | 86 |
|
97 | | - if user_input is not None: |
98 | | - if await validate_ip(user_input["ema_host"]): |
| 87 | + if user_input: |
| 88 | + retries = user_input.get(KEYS[2], 5) # Get port_retries from user input, default to 5 |
| 89 | + show_graphs = user_input.get(KEYS[5], False) # Get show_graphs from user input, default is False |
| 90 | + _LOGGER.warning("2. show_graphs = %s", show_graphs) |
| 91 | + ecu_id = await test_ecu_connection(self.hass, user_input["ecu_host"], retries, show_graphs) |
| 92 | + if ecu_id: |
99 | 93 | self.hass.config_entries.async_update_entry( |
100 | 94 | self.config_entry, data=user_input |
101 | 95 | ) |
102 | 96 | return self.async_create_entry(title="", data={}) |
| 97 | + else: |
| 98 | + errors["ecu_host"] = "no_ecu_found" |
| 99 | + return self.async_show_form( |
| 100 | + step_id="init", data_schema=STEP_USER_DATA_SCHEMA, errors=errors |
| 101 | + ) |
| 102 | + else: |
| 103 | + errors = {} |
| 104 | + return self.async_show_form( |
| 105 | + step_id="init", data_schema=schema, errors=errors |
| 106 | + ) |
| 107 | + |
103 | 108 |
|
104 | | - errors["base"] = "Could not connect to the specified EMA host" |
105 | | - return self.async_show_form(step_id="init", data_schema=schema, errors=errors) |
| 109 | +async def test_ecu_connection(hass, ecu_host, retries, show_graphs): |
| 110 | + """Test the connection to the ECU and return the ECU ID if successful.""" |
| 111 | + try: |
| 112 | + _LOGGER.warning("3. show_graphs = %s", show_graphs) |
| 113 | + ap_ecu = APsystemsSocket(ecu_host, show_graphs) |
| 114 | + # Pass the retries parameter dynamically |
| 115 | + _LOGGER.warning("4. show_graphs = %s", show_graphs) |
| 116 | + test_query = await ap_ecu.query_ecu(retries, show_graphs) |
| 117 | + ecu_id = test_query.get("ecu_id", None) |
| 118 | + return ecu_id |
| 119 | + |
| 120 | + except APsystemsInvalidData as err: |
| 121 | + _LOGGER.debug(f"APsystemsInvalidData exception: {err}") |
| 122 | + return None |
| 123 | + except Exception as err: |
| 124 | + _LOGGER.debug(f"Unknown error occurred during ECU query: {err}") |
| 125 | + return None |
0 commit comments