Small fixes for SwitchBot Locks (#84888)

Co-authored-by: Aaron Bach <bachya1208@gmail.com>
pull/85120/head
J. Nick Koston 2022-12-30 18:05:25 -10:00 committed by Paulus Schoutsen
parent 32736b3336
commit 9655619667
8 changed files with 72 additions and 26 deletions

View File

@ -45,7 +45,11 @@ PLATFORMS_BY_TYPE = {
SupportedModels.CONTACT.value: [Platform.BINARY_SENSOR, Platform.SENSOR],
SupportedModels.MOTION.value: [Platform.BINARY_SENSOR, Platform.SENSOR],
SupportedModels.HUMIDIFIER.value: [Platform.HUMIDIFIER, Platform.SENSOR],
SupportedModels.LOCK.value: [Platform.BINARY_SENSOR, Platform.LOCK],
SupportedModels.LOCK.value: [
Platform.BINARY_SENSOR,
Platform.LOCK,
Platform.SENSOR,
],
}
CLASS_BY_DEVICE = {
SupportedModels.CEILING_LIGHT.value: switchbot.SwitchbotCeilingLight,

View File

@ -5,7 +5,9 @@ import logging
from typing import Any
from switchbot import (
SwitchbotAccountConnectionError,
SwitchBotAdvertisement,
SwitchbotAuthenticationError,
SwitchbotLock,
SwitchbotModel,
parse_advertisement_data,
@ -100,7 +102,7 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
"address": short_address(discovery_info.address),
}
if model_name == SwitchbotModel.LOCK:
return await self.async_step_lock_chose_method()
return await self.async_step_lock_choose_method()
if self._discovered_adv.data["isEncrypted"]:
return await self.async_step_password()
return await self.async_step_confirm()
@ -172,11 +174,12 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
user_input[CONF_USERNAME],
user_input[CONF_PASSWORD],
)
except SwitchbotAccountConnectionError as ex:
raise AbortFlow("cannot_connect") from ex
except SwitchbotAuthenticationError:
errors = {"base": "auth_failed"}
else:
return await self.async_step_lock_key(key_details)
except RuntimeError:
errors = {
"base": "auth_failed",
}
user_input = user_input or {}
return self.async_show_form(
@ -195,14 +198,14 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
},
)
async def async_step_lock_chose_method(
async def async_step_lock_choose_method(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the SwitchBot API chose method step."""
assert self._discovered_adv is not None
return self.async_show_menu(
step_id="lock_chose_method",
step_id="lock_choose_method",
menu_options=["lock_auth", "lock_key"],
description_placeholders={
"name": name_from_discovery(self._discovered_adv),
@ -286,7 +289,7 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
device_adv = self._discovered_advs[user_input[CONF_ADDRESS]]
await self._async_set_device(device_adv)
if device_adv.data.get("modelName") == SwitchbotModel.LOCK:
return await self.async_step_lock_chose_method()
return await self.async_step_lock_choose_method()
if device_adv.data["isEncrypted"]:
return await self.async_step_password()
return await self._async_create_entry_from_discovery(user_input)
@ -298,7 +301,7 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
device_adv = list(self._discovered_advs.values())[0]
await self._async_set_device(device_adv)
if device_adv.data.get("modelName") == SwitchbotModel.LOCK:
return await self.async_step_lock_chose_method()
return await self.async_step_lock_choose_method()
if device_adv.data["isEncrypted"]:
return await self.async_step_password()
return await self.async_step_confirm()

View File

@ -2,7 +2,7 @@
"domain": "switchbot",
"name": "SwitchBot",
"documentation": "https://www.home-assistant.io/integrations/switchbot",
"requirements": ["PySwitchbot==0.34.1"],
"requirements": ["PySwitchbot==0.36.0"],
"config_flow": true,
"dependencies": ["bluetooth"],
"codeowners": [

View File

@ -30,11 +30,11 @@
"password": "[%key:common::config_flow::data::password%]"
}
},
"lock_chose_method": {
"description": "Choose configuration method, details can be found in the documentation.",
"lock_choose_method": {
"description": "A SwitchBot lock can be set up in Home Assistant in two different ways.\n\nYou can enter the key id and encryption key yourself, or Home Assistant can import them from your SwitchBot account.",
"menu_options": {
"lock_auth": "SwitchBot app login and password",
"lock_key": "Lock encryption key"
"lock_auth": "SwitchBot account (recommended)",
"lock_key": "Enter lock encryption key manually"
}
}
},

View File

@ -23,11 +23,11 @@
},
"description": "Please provide your SwitchBot app username and password. This data won't be saved and only used to retrieve your locks encryption key."
},
"lock_chose_method": {
"description": "Choose configuration method, details can be found in the documentation.",
"lock_choose_method": {
"description": "A SwitchBot lock can be set up in Home Assistant in two different ways.\n\nYou can enter the key id and encryption key yourself, or Home Assistant can import them from your SwitchBot account.",
"menu_options": {
"lock_auth": "SwitchBot app login and password",
"lock_key": "Lock encryption key"
"lock_auth": "SwitchBot account (recommended)",
"lock_key": "Enter lock encryption key manually"
}
},
"lock_key": {

View File

@ -40,7 +40,7 @@ PyRMVtransport==0.3.3
PySocks==1.7.1
# homeassistant.components.switchbot
PySwitchbot==0.34.1
PySwitchbot==0.36.0
# homeassistant.components.transport_nsw
PyTransportNSW==0.1.1

View File

@ -36,7 +36,7 @@ PyRMVtransport==0.3.3
PySocks==1.7.1
# homeassistant.components.switchbot
PySwitchbot==0.34.1
PySwitchbot==0.36.0
# homeassistant.components.transport_nsw
PyTransportNSW==0.1.1

View File

@ -2,6 +2,8 @@
from unittest.mock import patch
from switchbot import SwitchbotAccountConnectionError, SwitchbotAuthenticationError
from homeassistant.components.switchbot.const import (
CONF_ENCRYPTION_KEY,
CONF_KEY_ID,
@ -99,7 +101,7 @@ async def test_bluetooth_discovery_lock_key(hass):
data=WOLOCK_SERVICE_INFO,
)
assert result["type"] == FlowResultType.MENU
assert result["step_id"] == "lock_chose_method"
assert result["step_id"] == "lock_choose_method"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"next_step_id": "lock_key"}
@ -404,7 +406,7 @@ async def test_user_setup_wolock_key(hass):
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == FlowResultType.MENU
assert result["step_id"] == "lock_chose_method"
assert result["step_id"] == "lock_choose_method"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"next_step_id": "lock_key"}
@ -467,7 +469,7 @@ async def test_user_setup_wolock_auth(hass):
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == FlowResultType.MENU
assert result["step_id"] == "lock_chose_method"
assert result["step_id"] == "lock_choose_method"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"next_step_id": "lock_auth"}
@ -479,7 +481,7 @@ async def test_user_setup_wolock_auth(hass):
with patch(
"homeassistant.components.switchbot.config_flow.SwitchbotLock.retrieve_encryption_key",
side_effect=RuntimeError,
side_effect=SwitchbotAuthenticationError,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -524,6 +526,43 @@ async def test_user_setup_wolock_auth(hass):
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_setup_wolock_auth_switchbot_api_down(hass):
"""Test the user initiated form for a lock when the switchbot api is down."""
with patch(
"homeassistant.components.switchbot.config_flow.async_discovered_service_info",
return_value=[WOLOCK_SERVICE_INFO],
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == FlowResultType.MENU
assert result["step_id"] == "lock_choose_method"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"next_step_id": "lock_auth"}
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "lock_auth"
assert result["errors"] == {}
with patch(
"homeassistant.components.switchbot.config_flow.SwitchbotLock.retrieve_encryption_key",
side_effect=SwitchbotAccountConnectionError,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_USERNAME: "",
CONF_PASSWORD: "",
},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "cannot_connect"
async def test_user_setup_wolock_or_bot(hass):
"""Test the user initiated form for a lock."""
@ -547,7 +586,7 @@ async def test_user_setup_wolock_or_bot(hass):
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.MENU
assert result["step_id"] == "lock_chose_method"
assert result["step_id"] == "lock_choose_method"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"next_step_id": "lock_key"}