From 10d3b10da47b47f38ccee07b87056834cdd3c781 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sun, 4 Feb 2024 22:56:22 +0100 Subject: [PATCH] Improve Tuya token/reauth handling (#109653) --- homeassistant/components/tuya/__init__.py | 32 ++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/tuya/__init__.py b/homeassistant/components/tuya/__init__.py index ea38c117af7..5a6874fb352 100644 --- a/homeassistant/components/tuya/__init__.py +++ b/homeassistant/components/tuya/__init__.py @@ -59,12 +59,24 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: listener = DeviceListener(hass, manager) manager.add_device_listener(listener) + + # Get all devices from Tuya + try: + await hass.async_add_executor_job(manager.update_device_cache) + except Exception as exc: # pylint: disable=broad-except + # While in general, we should avoid catching broad exceptions, + # we have no other way of detecting this case. + if "sign invalid" in str(exc): + msg = "Authentication failed. Please re-authenticate" + raise ConfigEntryAuthFailed(msg) from exc + raise + + # Connection is successful, store the manager & listener hass.data.setdefault(DOMAIN, {})[entry.entry_id] = HomeAssistantTuyaData( manager=manager, listener=listener ) - # Get devices & clean up device entities - await hass.async_add_executor_job(manager.update_device_cache) + # Cleanup device registry await cleanup_device_registry(hass, manager) # Register known device IDs @@ -102,11 +114,25 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if tuya.manager.mq is not None: tuya.manager.mq.stop() tuya.manager.remove_device_listener(tuya.listener) - await hass.async_add_executor_job(tuya.manager.unload) del hass.data[DOMAIN][entry.entry_id] return unload_ok +async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Remove a config entry. + + This will revoke the credentials from Tuya. + """ + manager = Manager( + TUYA_CLIENT_ID, + entry.data[CONF_USER_CODE], + entry.data[CONF_TERMINAL_ID], + entry.data[CONF_ENDPOINT], + entry.data[CONF_TOKEN_INFO], + ) + await hass.async_add_executor_job(manager.unload) + + class DeviceListener(SharingDeviceListener): """Device Update Listener."""