From b6509aa1d0e33b7cb5bf52b8eeb30a20c2a9bf64 Mon Sep 17 00:00:00 2001 From: eriknn <82818949+eriknn@users.noreply.github.com> Date: Tue, 17 Dec 2024 23:33:49 +0100 Subject: [PATCH] Accept wrong pin --- custom_components/pax_ble/config_flow.py | 78 ++++++++++++++++-- custom_components/pax_ble/const.py | 1 + .../__pycache__/base_device.cpython-313.pyc | Bin 0 -> 15706 bytes .../__pycache__/calima.cpython-313.pyc | Bin 0 -> 10718 bytes .../characteristics.cpython-313.pyc | Bin 0 -> 1456 bytes .../__pycache__/svensa.cpython-313.pyc | Bin 0 -> 10046 bytes custom_components/pax_ble/strings.json | 18 ++++ .../pax_ble/translations/fi.json | 18 ++++ .../pax_ble/translations/nb.json | 18 ++++ .../pax_ble/translations/sv.json | 22 ++++- 10 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 custom_components/pax_ble/devices/__pycache__/base_device.cpython-313.pyc create mode 100644 custom_components/pax_ble/devices/__pycache__/calima.cpython-313.pyc create mode 100644 custom_components/pax_ble/devices/__pycache__/characteristics.cpython-313.pyc create mode 100644 custom_components/pax_ble/devices/__pycache__/svensa.cpython-313.pyc diff --git a/custom_components/pax_ble/config_flow.py b/custom_components/pax_ble/config_flow.py index 32789b1..6bbf23e 100644 --- a/custom_components/pax_ble/config_flow.py +++ b/custom_components/pax_ble/config_flow.py @@ -15,7 +15,7 @@ from .devices.base_device import BaseDevice from homeassistant.const import CONF_DEVICES -from .const import CONF_ACTION, CONF_ADD_DEVICE, CONF_EDIT_DEVICE, CONF_REMOVE_DEVICE +from .const import CONF_ACTION, CONF_ADD_DEVICE, CONF_WRONG_PIN_SELECTOR, CONF_EDIT_DEVICE, CONF_REMOVE_DEVICE from .const import DOMAIN, CONF_NAME, CONF_MODEL, CONF_MAC, CONF_PIN, CONF_SCAN_INTERVAL, CONF_SCAN_INTERVAL_FAST from .const import DEFAULT_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL_FAST from .const import DeviceModel @@ -41,6 +41,7 @@ class PaxConfigFlowHandler(ConfigFlow, domain=DOMAIN): def __init__(self): self.device_data = DEVICE_DATA.copy() # Data of "current" device self.config_entry = None + self.accept_wrong_pin = False def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: """Get the options flow for this handler.""" @@ -107,7 +108,11 @@ async def async_step_add_device(self, user_input=None): if await fan.connect(): await fan.setAuth(user_input[CONF_PIN]) - pin_verified = await fan.checkAuth() + + if not self.accept_wrong_pin: + pin_verified = await fan.checkAuth() + else: + pin_verified = True await fan.disconnect() if pin_verified: @@ -143,9 +148,10 @@ async def async_step_add_device(self, user_input=None): } ) else: - errors["base"] = "wrong_pin" - # Store values for new attempt + # Store values for accept / decline wrong pin self.device_data = user_input + errors["base"] = "wrong_pin" + return await self.async_step_wrong_pin() else: errors["base"] = "cannot_connect" # Store values for new attempt @@ -156,10 +162,30 @@ async def async_step_add_device(self, user_input=None): step_id="add_device", data_schema=data_schema, errors=errors ) + """################################################## + ###################### WRONG PIN #################### + ##################################################""" + async def async_step_wrong_pin(self, user_input=None): + """Accept or decline wrong pin.""" + errors = {} + + if user_input is not None: + if user_input.get(CONF_WRONG_PIN_SELECTOR) == "accept": + self.accept_wrong_pin = True + return await self.async_step_add_device(self.device_data) + if user_input.get(CONF_WRONG_PIN_SELECTOR) == "decline": + self.accept_wrong_pin = False + return await self.async_step_add_device() + + return self.async_show_form( + step_id="wrong_pin", data_schema=MENU_WRONG_PIN_SCHEMA, errors=errors + ) + class PaxOptionsFlowHandler(OptionsFlow): def __init__(self): self.selected_device = None # Mac address / key self.device_data = DEVICE_DATA.copy() # Data of "current" device + self.accept_wrong_pin = False async def async_step_init(self, user_input: dict[str, Any] | None = None): # Manage the options for the custom component.""" @@ -198,7 +224,11 @@ async def async_step_add_device(self, user_input=None): if await fan.connect(): await fan.setAuth(user_input[CONF_PIN]) - pin_verified = await fan.checkAuth() + + if not self.accept_wrong_pin: + pin_verified = await fan.checkAuth() + else: + pin_verified = True await fan.disconnect() if pin_verified: @@ -216,9 +246,10 @@ async def async_step_add_device(self, user_input=None): } ) else: - errors["base"] = "wrong_pin" - # Store values for new attempt + # Store values for accept / decline wrong pin self.device_data = user_input + errors["base"] = "wrong_pin" + return await self.async_step_wrong_pin() else: errors["base"] = "cannot_connect" # Store values for new attempt @@ -229,6 +260,25 @@ async def async_step_add_device(self, user_input=None): step_id="add_device", data_schema=data_schema, errors=errors ) + """################################################## + ###################### WRONG PIN #################### + ##################################################""" + async def async_step_wrong_pin(self, user_input=None): + """Accept or decline wrong pin.""" + errors = {} + + if user_input is not None: + if user_input.get(CONF_WRONG_PIN_SELECTOR) == "accept": + self.accept_wrong_pin = True + return await self.async_step_add_device(self.device_data) + if user_input.get(CONF_WRONG_PIN_SELECTOR) == "decline": + self.accept_wrong_pin = False + return await self.async_step_add_device() + + return self.async_show_form( + step_id="wrong_pin", data_schema=MENU_WRONG_PIN_SCHEMA, errors=errors + ) + """################################################## ################# SELECT EDIT DEVICE ################ ##################################################""" @@ -260,6 +310,7 @@ async def async_step_edit_device(self, user_input=None): if user_input is not None: # Update device in config entry new_data = self.config_entry.data.copy() + new_data[CONF_DEVICES][self.selected_device][CONF_PIN] = user_input[CONF_PIN] new_data[CONF_DEVICES][self.selected_device][CONF_SCAN_INTERVAL] = user_input[CONF_SCAN_INTERVAL] new_data[CONF_DEVICES][self.selected_device][CONF_SCAN_INTERVAL_FAST] = user_input[CONF_SCAN_INTERVAL_FAST] @@ -384,6 +435,9 @@ def getDeviceSchemaAdd(user_input: dict[str, Any] | None = None) -> vol.Schema: def getDeviceSchemaEdit(user_input: dict[str, Any] | None = None) -> vol.Schema: data_schema = vol.Schema( { + vol.Required( + CONF_PIN, description="Pin Code", default=user_input[CONF_PIN] + ): cv.string, vol.Optional( CONF_SCAN_INTERVAL, default=user_input[CONF_SCAN_INTERVAL] ): vol.All(vol.Coerce(int), vol.Range(min=5, max=999)), @@ -408,3 +462,13 @@ def getDeviceSchemaSelect(devices: dict[str, Any] | None = None) -> vol.Schema: ) return data_schema + +# Schema for accepting wrong pin +MENU_WRONG_PIN_VALUES = ["accept", "decline"] +MENU_WRONG_PIN_SCHEMA = vol.Schema( + { + vol.Required(CONF_WRONG_PIN_SELECTOR): selector.SelectSelector( + selector.SelectSelectorConfig(options=MENU_WRONG_PIN_VALUES, translation_key=CONF_WRONG_PIN_SELECTOR), + ) + } +) \ No newline at end of file diff --git a/custom_components/pax_ble/const.py b/custom_components/pax_ble/const.py index cb31980..91a44e3 100644 --- a/custom_components/pax_ble/const.py +++ b/custom_components/pax_ble/const.py @@ -8,6 +8,7 @@ # Configuration Constants CONF_ACTION = "action" CONF_ADD_DEVICE = "add_device" +CONF_WRONG_PIN_SELECTOR = "wrong_pin_selector" CONF_EDIT_DEVICE = "edit_device" CONF_REMOVE_DEVICE = "remove_device" diff --git a/custom_components/pax_ble/devices/__pycache__/base_device.cpython-313.pyc b/custom_components/pax_ble/devices/__pycache__/base_device.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91be8fed146d5572a4728738d91db4d60fe5ef1b GIT binary patch literal 15706 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 W-mGEIdEKv76H0p5dlcqm-v0rnKR8GL literal 0 HcmV?d00001 diff --git a/custom_components/pax_ble/devices/__pycache__/calima.cpython-313.pyc b/custom_components/pax_ble/devices/__pycache__/calima.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b877c5cc7bf55fbfc66f930b4d494173244a89ea GIT binary patch literal 10718 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 ZvFA+6eD