1
mirror of https://github.com/home-assistant/core synced 2024-07-27 18:58:57 +02:00

Add authentication support to bsblan (#42306)

This commit is contained in:
Willem-Jan 2020-11-30 20:13:16 +01:00 committed by GitHub
parent 434cec7a88
commit ba4d630470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 186 additions and 10 deletions

View File

@ -5,7 +5,7 @@ from bsblan import BSBLan, BSBLanConnectionError
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
@ -29,6 +29,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.data[CONF_HOST],
passkey=entry.data[CONF_PASSKEY],
port=entry.data[CONF_PORT],
username=entry.data.get(CONF_USERNAME),
password=entry.data.get(CONF_PASSWORD),
session=session,
)

View File

@ -6,7 +6,7 @@ from bsblan import BSBLan, BSBLanError, Info
import voluptuous as vol
from homeassistant.config_entries import CONN_CLASS_LOCAL_POLL, ConfigFlow
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import ConfigType
@ -37,6 +37,8 @@ class BSBLanFlowHandler(ConfigFlow, domain=DOMAIN):
host=user_input[CONF_HOST],
port=user_input[CONF_PORT],
passkey=user_input.get(CONF_PASSKEY),
username=user_input.get(CONF_USERNAME),
password=user_input.get(CONF_PASSWORD),
)
except BSBLanError:
return self._show_setup_form({"base": "cannot_connect"})
@ -52,6 +54,8 @@ class BSBLanFlowHandler(ConfigFlow, domain=DOMAIN):
CONF_PORT: user_input[CONF_PORT],
CONF_PASSKEY: user_input.get(CONF_PASSKEY),
CONF_DEVICE_IDENT: info.device_identification,
CONF_USERNAME: user_input.get(CONF_USERNAME),
CONF_PASSWORD: user_input.get(CONF_PASSWORD),
},
)
@ -64,16 +68,30 @@ class BSBLanFlowHandler(ConfigFlow, domain=DOMAIN):
vol.Required(CONF_HOST): str,
vol.Optional(CONF_PORT, default=80): int,
vol.Optional(CONF_PASSKEY): str,
vol.Optional(CONF_USERNAME): str,
vol.Optional(CONF_PASSWORD): str,
}
),
errors=errors or {},
)
async def _get_bsblan_info(
self, host: str, passkey: Optional[str], port: int
self,
host: str,
username: Optional[str],
password: Optional[str],
passkey: Optional[str],
port: int,
) -> Info:
"""Get device information from an BSBLan device."""
session = async_get_clientsession(self.hass)
_LOGGER.debug("request bsblan.info:")
bsblan = BSBLan(host, passkey=passkey, port=port, session=session)
bsblan = BSBLan(
host,
username=username,
password=password,
passkey=passkey,
port=port,
session=session,
)
return await bsblan.info()

View File

@ -8,7 +8,9 @@
"data": {
"host": "[%key:common::config_flow::data::host%]",
"port": "[%key:common::config_flow::data::port%]",
"passkey": "Passkey string"
"passkey": "Passkey string",
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
}
}
},

View File

@ -5,7 +5,13 @@ from homeassistant.components.bsblan.const import (
CONF_PASSKEY,
DOMAIN,
)
from homeassistant.const import CONF_HOST, CONF_PORT, CONTENT_TYPE_JSON
from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_USERNAME,
CONTENT_TYPE_JSON,
)
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
@ -26,6 +32,42 @@ async def init_integration(
headers={"Content-Type": CONTENT_TYPE_JSON},
)
entry = MockConfigEntry(
domain=DOMAIN,
unique_id="RVS21.831F/127",
data={
CONF_HOST: "example.local",
CONF_USERNAME: "nobody",
CONF_PASSWORD: "qwerty",
CONF_PASSKEY: "1234",
CONF_PORT: 80,
CONF_DEVICE_IDENT: "RVS21.831F/127",
},
)
entry.add_to_hass(hass)
if not skip_setup:
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
return entry
async def init_integration_without_auth(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
skip_setup: bool = False,
) -> MockConfigEntry:
"""Set up the BSBLan integration in Home Assistant."""
aioclient_mock.post(
"http://example.local:80/1234/JQ?Parameter=6224,6225,6226",
params={"Parameter": "6224,6225,6226"},
text=load_fixture("bsblan/info.json"),
headers={"Content-Type": CONTENT_TYPE_JSON},
)
entry = MockConfigEntry(
domain=DOMAIN,
unique_id="RVS21.831F/127",

View File

@ -5,7 +5,13 @@ from homeassistant import data_entry_flow
from homeassistant.components.bsblan import config_flow
from homeassistant.components.bsblan.const import CONF_DEVICE_IDENT, CONF_PASSKEY
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_HOST, CONF_PORT, CONTENT_TYPE_JSON
from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_USERNAME,
CONTENT_TYPE_JSON,
)
from homeassistant.core import HomeAssistant
from . import init_integration
@ -37,7 +43,13 @@ async def test_connection_error(
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: "example.local", CONF_PASSKEY: "1234", CONF_PORT: 80},
data={
CONF_HOST: "example.local",
CONF_USERNAME: "nobody",
CONF_PASSWORD: "qwerty",
CONF_PASSKEY: "1234",
CONF_PORT: 80,
},
)
assert result["errors"] == {"base": "cannot_connect"}
@ -54,7 +66,13 @@ async def test_user_device_exists_abort(
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: "example.local", CONF_PASSKEY: "1234", CONF_PORT: 80},
data={
CONF_HOST: "example.local",
CONF_USERNAME: "nobody",
CONF_PASSWORD: "qwerty",
CONF_PASSKEY: "1234",
CONF_PORT: 80,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
@ -80,10 +98,18 @@ async def test_full_user_flow_implementation(
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: "example.local", CONF_PASSKEY: "1234", CONF_PORT: 80},
user_input={
CONF_HOST: "example.local",
CONF_USERNAME: "nobody",
CONF_PASSWORD: "qwerty",
CONF_PASSKEY: "1234",
CONF_PORT: 80,
},
)
assert result["data"][CONF_HOST] == "example.local"
assert result["data"][CONF_USERNAME] == "nobody"
assert result["data"][CONF_PASSWORD] == "qwerty"
assert result["data"][CONF_PASSKEY] == "1234"
assert result["data"][CONF_PORT] == 80
assert result["data"][CONF_DEVICE_IDENT] == "RVS21.831F/127"
@ -92,3 +118,42 @@ async def test_full_user_flow_implementation(
entries = hass.config_entries.async_entries(config_flow.DOMAIN)
assert entries[0].unique_id == "RVS21.831F/127"
async def test_full_user_flow_implementation_without_auth(
hass: HomeAssistant, aioclient_mock
) -> None:
"""Test the full manual user flow from start to finish."""
aioclient_mock.post(
"http://example2.local:80/JQ?Parameter=6224,6225,6226",
text=load_fixture("bsblan/info.json"),
headers={"Content-Type": CONTENT_TYPE_JSON},
)
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": SOURCE_USER},
)
assert result["step_id"] == "user"
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_HOST: "example2.local",
CONF_PORT: 80,
},
)
assert result["data"][CONF_HOST] == "example2.local"
assert result["data"][CONF_USERNAME] is None
assert result["data"][CONF_PASSWORD] is None
assert result["data"][CONF_PASSKEY] is None
assert result["data"][CONF_PORT] == 80
assert result["data"][CONF_DEVICE_IDENT] == "RVS21.831F/127"
assert result["title"] == "RVS21.831F/127"
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
entries = hass.config_entries.async_entries(config_flow.DOMAIN)
assert entries[0].unique_id == "RVS21.831F/127"

View File

@ -0,0 +1,47 @@
"""Tests for the BSBLan integration."""
import aiohttp
from homeassistant.components.bsblan.const import DOMAIN
from homeassistant.config_entries import ENTRY_STATE_SETUP_RETRY
from homeassistant.core import HomeAssistant
from tests.components.bsblan import init_integration, init_integration_without_auth
from tests.test_util.aiohttp import AiohttpClientMocker
async def test_config_entry_not_ready(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the BSBLan configuration entry not ready."""
aioclient_mock.post(
"http://example.local:80/1234/JQ?Parameter=6224,6225,6226",
exc=aiohttp.ClientError,
)
entry = await init_integration(hass, aioclient_mock)
assert entry.state == ENTRY_STATE_SETUP_RETRY
async def test_unload_config_entry(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the BSBLan configuration entry unloading."""
entry = await init_integration(hass, aioclient_mock)
assert hass.data[DOMAIN]
await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
assert not hass.data.get(DOMAIN)
async def test_config_entry_no_authentication(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the BSBLan configuration entry not ready."""
aioclient_mock.post(
"http://example.local:80/1234/JQ?Parameter=6224,6225,6226",
exc=aiohttp.ClientError,
)
entry = await init_integration_without_auth(hass, aioclient_mock)
assert entry.state == ENTRY_STATE_SETUP_RETRY