mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Show HomeKit Controller unhandled pairing error reason in the UI (#82505)
This commit is contained in:
parent
a7caa038be
commit
7df711f1f3
@ -420,6 +420,7 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
# Should never call this step without setting self.hkid
|
# Should never call this step without setting self.hkid
|
||||||
assert self.hkid
|
assert self.hkid
|
||||||
|
description_placeholders = {}
|
||||||
|
|
||||||
errors = {}
|
errors = {}
|
||||||
|
|
||||||
@ -465,10 +466,11 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
return self.async_abort(reason="accessory_not_found_error")
|
return self.async_abort(reason="accessory_not_found_error")
|
||||||
except InsecureSetupCode:
|
except InsecureSetupCode:
|
||||||
errors["pairing_code"] = "insecure_setup_code"
|
errors["pairing_code"] = "insecure_setup_code"
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
_LOGGER.exception("Pairing attempt failed with an unhandled exception")
|
_LOGGER.exception("Pairing attempt failed with an unhandled exception")
|
||||||
self.finish_pairing = None
|
self.finish_pairing = None
|
||||||
errors["pairing_code"] = "pairing_failed"
|
errors["pairing_code"] = "pairing_failed"
|
||||||
|
description_placeholders["error"] = str(err)
|
||||||
|
|
||||||
if not self.finish_pairing:
|
if not self.finish_pairing:
|
||||||
# Its possible that the first try may have been busy so
|
# Its possible that the first try may have been busy so
|
||||||
@ -496,11 +498,12 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
# TLV error, usually not in pairing mode
|
# TLV error, usually not in pairing mode
|
||||||
_LOGGER.exception("Pairing communication failed")
|
_LOGGER.exception("Pairing communication failed")
|
||||||
return await self.async_step_protocol_error()
|
return await self.async_step_protocol_error()
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
_LOGGER.exception("Pairing attempt failed with an unhandled exception")
|
_LOGGER.exception("Pairing attempt failed with an unhandled exception")
|
||||||
errors["pairing_code"] = "pairing_failed"
|
errors["pairing_code"] = "pairing_failed"
|
||||||
|
description_placeholders["error"] = str(err)
|
||||||
|
|
||||||
return self._async_step_pair_show_form(errors)
|
return self._async_step_pair_show_form(errors, description_placeholders)
|
||||||
|
|
||||||
async def async_step_busy_error(
|
async def async_step_busy_error(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
@ -531,7 +534,9 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_step_pair_show_form(
|
def _async_step_pair_show_form(
|
||||||
self, errors: dict[str, str] | None = None
|
self,
|
||||||
|
errors: dict[str, str] | None = None,
|
||||||
|
description_placeholders: dict[str, str] | None = None,
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
assert self.category
|
assert self.category
|
||||||
|
|
||||||
@ -547,7 +552,7 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="pair",
|
step_id="pair",
|
||||||
errors=errors or {},
|
errors=errors or {},
|
||||||
description_placeholders=placeholders,
|
description_placeholders=placeholders | (description_placeholders or {}),
|
||||||
data_schema=vol.Schema(schema),
|
data_schema=vol.Schema(schema),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
"unknown_error": "Device reported an unknown error. Pairing failed.",
|
"unknown_error": "Device reported an unknown error. Pairing failed.",
|
||||||
"authentication_error": "Incorrect HomeKit code. Please check it and try again.",
|
"authentication_error": "Incorrect HomeKit code. Please check it and try again.",
|
||||||
"max_peers_error": "Device refused to add pairing as it has no free pairing storage.",
|
"max_peers_error": "Device refused to add pairing as it has no free pairing storage.",
|
||||||
"pairing_failed": "An unhandled error occurred while attempting to pair with this device. This may be a temporary failure or your device may not be supported currently."
|
"pairing_failed": "An unhandled error occurred while attempting to pair with this device. This may be a temporary failure or your device may not be supported currently: {error}"
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"no_devices": "No unpaired devices could be found",
|
"no_devices": "No unpaired devices could be found",
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"authentication_error": "Incorrect HomeKit code. Please check it and try again.",
|
"authentication_error": "Incorrect HomeKit code. Please check it and try again.",
|
||||||
"insecure_setup_code": "The requested setup code is insecure because of its trivial nature. This accessory fails to meet basic security requirements.",
|
"insecure_setup_code": "The requested setup code is insecure because of its trivial nature. This accessory fails to meet basic security requirements.",
|
||||||
"max_peers_error": "Device refused to add pairing as it has no free pairing storage.",
|
"max_peers_error": "Device refused to add pairing as it has no free pairing storage.",
|
||||||
"pairing_failed": "An unhandled error occurred while attempting to pair with this device. This may be a temporary failure or your device may not be supported currently.",
|
"pairing_failed": "An unhandled error occurred while attempting to pair with this device. This may be a temporary failure or your device may not be supported currently: {error}",
|
||||||
"unable_to_pair": "Unable to pair, please try again.",
|
"unable_to_pair": "Unable to pair, please try again.",
|
||||||
"unknown_error": "Device reported an unknown error. Pairing failed."
|
"unknown_error": "Device reported an unknown error. Pairing failed."
|
||||||
},
|
},
|
||||||
|
@ -8,6 +8,7 @@ from aiohomekit.exceptions import AuthenticationError
|
|||||||
from aiohomekit.model import Accessories, Accessory
|
from aiohomekit.model import Accessories, Accessory
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
from aiohomekit.model.services import ServicesTypes
|
from aiohomekit.model.services import ServicesTypes
|
||||||
|
from bleak.exc import BleakError
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
@ -743,6 +744,57 @@ async def test_pair_form_errors_on_finish(hass, controller, exception, expected)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_pair_unknown_errors(hass, controller):
|
||||||
|
"""Test describing unknown errors."""
|
||||||
|
device = setup_mock_accessory(controller)
|
||||||
|
discovery_info = get_device_discovery_info(device)
|
||||||
|
|
||||||
|
# Device is discovered
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
"homekit_controller",
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=discovery_info,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert get_flow_context(hass, result) == {
|
||||||
|
"title_placeholders": {"name": "TestDevice", "category": "Outlet"},
|
||||||
|
"unique_id": "00:00:00:00:00:00",
|
||||||
|
"source": config_entries.SOURCE_ZEROCONF,
|
||||||
|
}
|
||||||
|
|
||||||
|
# User initiates pairing - this triggers the device to show a pairing code
|
||||||
|
# and then HA to show a pairing form
|
||||||
|
finish_pairing = unittest.mock.AsyncMock(
|
||||||
|
side_effect=BleakError("The bluetooth connection failed")
|
||||||
|
)
|
||||||
|
with patch.object(device, "async_start_pairing", return_value=finish_pairing):
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert get_flow_context(hass, result) == {
|
||||||
|
"title_placeholders": {"name": "TestDevice", "category": "Outlet"},
|
||||||
|
"unique_id": "00:00:00:00:00:00",
|
||||||
|
"source": config_entries.SOURCE_ZEROCONF,
|
||||||
|
}
|
||||||
|
|
||||||
|
# User enters pairing code
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={"pairing_code": "111-22-333"}
|
||||||
|
)
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["errors"]["pairing_code"] == "pairing_failed"
|
||||||
|
assert (
|
||||||
|
result["description_placeholders"]["error"] == "The bluetooth connection failed"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert get_flow_context(hass, result) == {
|
||||||
|
"title_placeholders": {"name": "TestDevice", "category": "Outlet"},
|
||||||
|
"unique_id": "00:00:00:00:00:00",
|
||||||
|
"source": config_entries.SOURCE_ZEROCONF,
|
||||||
|
"pairing": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_user_works(hass, controller):
|
async def test_user_works(hass, controller):
|
||||||
"""Test user initiated disovers devices."""
|
"""Test user initiated disovers devices."""
|
||||||
setup_mock_accessory(controller)
|
setup_mock_accessory(controller)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user