Fix Tuya QR code expiry, use native QR selector (#109615)

* Fix Tuya QR code expiry, use native QR selector

* Adjust tests
pull/109625/head
Franck Nijhof 2024-02-04 18:58:09 +01:00 committed by GitHub
parent e96f574a79
commit b553bb71e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 28 additions and 39 deletions

View File

@ -2,15 +2,14 @@
from __future__ import annotations
from collections.abc import Mapping
from io import BytesIO
from typing import Any
import segno
from tuya_sharing import LoginControl
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry, ConfigFlow
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import selector
from .const import (
CONF_ENDPOINT,
@ -33,7 +32,6 @@ class TuyaConfigFlow(ConfigFlow, domain=DOMAIN):
__user_code: str
__qr_code: str
__qr_image: str
__reauth_entry: ConfigEntry | None = None
def __init__(self) -> None:
@ -82,9 +80,17 @@ class TuyaConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input is None:
return self.async_show_form(
step_id="scan",
description_placeholders={
TUYA_RESPONSE_QR_CODE: self.__qr_image,
},
data_schema=vol.Schema(
{
vol.Optional("QR"): selector.QrCodeSelector(
config=selector.QrCodeSelectorConfig(
data=f"tuyaSmart--qrLogin?token={self.__qr_code}",
scale=5,
error_correction_level=selector.QrErrorCorrectionLevel.QUARTILE,
)
)
}
),
)
ret, info = await self.hass.async_add_executor_job(
@ -94,11 +100,23 @@ class TuyaConfigFlow(ConfigFlow, domain=DOMAIN):
self.__user_code,
)
if not ret:
# Try to get a new QR code on failure
await self.__async_get_qr_code(self.__user_code)
return self.async_show_form(
step_id="scan",
errors={"base": "login_error"},
data_schema=vol.Schema(
{
vol.Optional("QR"): selector.QrCodeSelector(
config=selector.QrCodeSelectorConfig(
data=f"tuyaSmart--qrLogin?token={self.__qr_code}",
scale=5,
error_correction_level=selector.QrErrorCorrectionLevel.QUARTILE,
)
)
}
),
description_placeholders={
TUYA_RESPONSE_QR_CODE: self.__qr_image,
TUYA_RESPONSE_MSG: info.get(TUYA_RESPONSE_MSG, "Unknown error"),
TUYA_RESPONSE_CODE: info.get(TUYA_RESPONSE_CODE, 0),
},
@ -189,24 +207,4 @@ class TuyaConfigFlow(ConfigFlow, domain=DOMAIN):
if success := response.get(TUYA_RESPONSE_SUCCESS, False):
self.__user_code = user_code
self.__qr_code = response[TUYA_RESPONSE_RESULT][TUYA_RESPONSE_QR_CODE]
self.__qr_image = _generate_qr_code(self.__qr_code)
return success, response
def _generate_qr_code(data: str) -> str:
"""Create an SVG QR code that can be scanned with the Smart Life app."""
qr_code = segno.make(f"tuyaSmart--qrLogin?token={data}", error="h")
with BytesIO() as buffer:
qr_code.save(
buffer,
kind="svg",
border=5,
scale=5,
xmldecl=False,
svgns=False,
svgclass=None,
lineclass=None,
svgversion=2,
dark="#1abcf2",
)
return str(buffer.getvalue().decode("ascii"))

View File

@ -43,5 +43,5 @@
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["tuya_iot"],
"requirements": ["tuya-device-sharing-sdk==0.1.9", "segno==1.5.3"]
"requirements": ["tuya-device-sharing-sdk==0.1.9"]
}

View File

@ -14,7 +14,7 @@
}
},
"scan": {
"description": "Use Smart Life app or Tuya Smart app to scan the following QR-code to complete the login:\n\n {qrcode} \n\nContinue to the next step once you have completed this step in the app."
"description": "Use Smart Life app or Tuya Smart app to scan the following QR-code to complete the login.\n\nContinue to the next step once you have completed this step in the app."
}
},
"error": {

View File

@ -2494,9 +2494,6 @@ scsgate==0.1.0
# homeassistant.components.backup
securetar==2023.3.0
# homeassistant.components.tuya
segno==1.5.3
# homeassistant.components.sendgrid
sendgrid==6.8.2

View File

@ -1901,9 +1901,6 @@ screenlogicpy==0.10.0
# homeassistant.components.backup
securetar==2023.3.0
# homeassistant.components.tuya
segno==1.5.3
# homeassistant.components.emulated_kasa
# homeassistant.components.sense
sense-energy==0.12.2

View File

@ -11,7 +11,7 @@ from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import ANY, MockConfigEntry
from tests.common import MockConfigEntry
pytestmark = pytest.mark.usefixtures("mock_setup_entry")
@ -37,7 +37,6 @@ async def test_user_flow(
assert result2.get("type") == FlowResultType.FORM
assert result2.get("step_id") == "scan"
assert result2.get("description_placeholders") == {"qrcode": ANY}
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -157,7 +156,6 @@ async def test_reauth_flow(
assert result.get("type") == FlowResultType.FORM
assert result.get("step_id") == "scan"
assert result.get("description_placeholders") == {"qrcode": ANY}
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -206,7 +204,6 @@ async def test_reauth_flow_migration(
assert result2.get("type") == FlowResultType.FORM
assert result2.get("step_id") == "scan"
assert result2.get("description_placeholders") == {"qrcode": ANY}
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],