Skip to content

Commit e96447d

Browse files
committed
Xiaomi authorization has been completely rewritten
1 parent e280bbc commit e96447d

File tree

12 files changed

+423
-235
lines changed

12 files changed

+423
-235
lines changed

custom_components/xiaomi_gateway3/config_flow.py

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import base64
2+
13
import homeassistant.helpers.config_validation as cv
24
import voluptuous as vol
35
from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow
@@ -6,7 +8,7 @@
68

79
from .core import core_utils
810
from .core.const import DOMAIN, PID_BLE, PID_WIFI, PID_WIFI_BLE
9-
from .core.xiaomi_cloud import MiCloud
11+
from .core.xiaomi_cloud import AuthResult, MiCloud
1012
from .hass import hass_utils
1113

1214
SERVERS = {
@@ -19,7 +21,7 @@
1921
}
2022

2123

22-
def vol_schema(schema: dict, defaults: dict | None) -> vol.Schema:
24+
def vol_schema(schema: dict, defaults: dict = None) -> vol.Schema:
2325
if defaults:
2426
for key in schema:
2527
if (value := defaults.get(key.schema)) is not None:
@@ -30,6 +32,9 @@ def vol_schema(schema: dict, defaults: dict | None) -> vol.Schema:
3032
class FlowHandler(ConfigFlow, domain=DOMAIN):
3133
VERSION = 4
3234

35+
cloud: MiCloud = None
36+
cloud_user_input: dict = None
37+
3338
cloud_gateways: list[dict] = None
3439

3540
async def async_step_user(self, user_input: dict = None):
@@ -66,36 +71,74 @@ async def async_step_user(self, user_input: dict = None):
6671
),
6772
)
6873

74+
def _show_cloud_form(self, defaults: dict, errors: dict = None):
75+
return self.async_show_form(
76+
step_id="cloud",
77+
data_schema=vol_schema(
78+
{
79+
vol.Required("username"): str,
80+
vol.Required("password"): str,
81+
vol.Required("servers", default=["cn"]): cv.multi_select(SERVERS),
82+
},
83+
defaults,
84+
),
85+
errors=errors,
86+
)
87+
88+
async def _process_cloud_result(self, result: AuthResult | None):
89+
if result["ok"]:
90+
return self.async_create_entry(
91+
title=self.cloud_user_input["username"],
92+
data={
93+
"username": self.cloud_user_input["username"],
94+
"servers": self.cloud_user_input["servers"],
95+
"token": result["token"],
96+
},
97+
)
98+
99+
if image := result.get("captcha"):
100+
image = "data:image/jpeg;base64," + base64.b64encode(image).decode()
101+
return self.async_show_form(
102+
step_id="cloud_captcha",
103+
data_schema=vol_schema({vol.Required("code"): str}),
104+
description_placeholders={"image": image},
105+
)
106+
107+
if email := result.get("email"):
108+
return self.async_show_form(
109+
step_id="cloud_email",
110+
data_schema=vol_schema({vol.Required("code"): str}),
111+
description_placeholders={"email": email},
112+
)
113+
114+
return self._show_cloud_form(
115+
self.cloud_user_input, errors={"base": "cant_login"}
116+
)
117+
69118
async def async_step_cloud(self, user_input: dict = None):
70-
kwargs = {"description_placeholders": {"verify": ""}}
119+
if not user_input:
120+
return self._show_cloud_form(user_input)
71121

72-
if user_input:
73-
if user_input["servers"]:
74-
session = async_create_clientsession(self.hass)
75-
cloud = MiCloud(session)
76-
if await cloud.login(user_input["username"], user_input["password"]):
77-
return self.async_create_entry(
78-
title=user_input["username"], data=user_input
79-
)
80-
elif cloud.verify:
81-
msg = f"\n[Verify url]({cloud.verify})"
82-
kwargs["description_placeholders"]["verify"] = msg
83-
kwargs["errors"] = {"base": "verify"}
84-
else:
85-
kwargs["errors"] = {"base": "cant_login"}
86-
else:
87-
kwargs["errors"] = {"base": "no_servers"}
122+
if not user_input["servers"]:
123+
return self._show_cloud_form(user_input, {"base": "no_servers"})
88124

89-
data = vol_schema(
90-
{
91-
vol.Required("username"): str,
92-
vol.Required("password"): str,
93-
vol.Required("servers", default=["cn"]): cv.multi_select(SERVERS),
94-
},
95-
user_input,
125+
if not self.cloud:
126+
self.cloud = MiCloud(async_create_clientsession(self.hass))
127+
128+
self.cloud_user_input = user_input
129+
130+
result = await self.cloud.login(
131+
user_input["username"], self.cloud_user_input["password"]
96132
)
133+
return await self._process_cloud_result(result)
134+
135+
async def async_step_cloud_captcha(self, user_input: dict = None):
136+
result = await self.cloud.login_captcha(user_input["code"])
137+
return await self._process_cloud_result(result)
97138

98-
return self.async_show_form(step_id="cloud", data_schema=data, **kwargs)
139+
async def async_step_cloud_email(self, user_input: dict = None):
140+
result = await self.cloud.verify_email(user_input["code"])
141+
return await self._process_cloud_result(result)
99142

100143
async def async_step_token(self, user_input: dict = None):
101144
"""GUI > Configuration > Integrations > Plus > Xiaomi Gateway 3"""

0 commit comments

Comments
 (0)