From 93f8d21bc0f4dfc35a2a57eb093911c9f2f3012d Mon Sep 17 00:00:00 2001 From: Fredrik Erlandsson Date: Mon, 11 May 2020 19:39:20 +0200 Subject: [PATCH] Bump pydaikin to 2.0.1, catch HTTPForbidden exception (#35466) --- .../components/daikin/config_flow.py | 40 ++++++++++++------- homeassistant/components/daikin/manifest.json | 2 +- homeassistant/components/daikin/strings.json | 17 ++++---- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/daikin/test_config_flow.py | 32 ++++++++++----- 6 files changed, 60 insertions(+), 35 deletions(-) diff --git a/homeassistant/components/daikin/config_flow.py b/homeassistant/components/daikin/config_flow.py index 600c27b1619..8dc491ac868 100644 --- a/homeassistant/components/daikin/config_flow.py +++ b/homeassistant/components/daikin/config_flow.py @@ -3,7 +3,7 @@ import asyncio import logging from uuid import uuid4 -from aiohttp import ClientError +from aiohttp import ClientError, web_exceptions from async_timeout import timeout from pydaikin.daikin_base import Appliance import voluptuous as vol @@ -15,6 +15,14 @@ from .const import CONF_KEY, CONF_UUID, KEY_IP, KEY_MAC, TIMEOUT _LOGGER = logging.getLogger(__name__) +DATA_SCHEMA = vol.Schema( + { + vol.Required(CONF_HOST): str, + vol.Optional(CONF_KEY): str, + vol.Optional(CONF_PASSWORD): str, + } +) + @config_entries.HANDLERS.register("daikin") class FlowHandler(config_entries.ConfigFlow): @@ -43,7 +51,6 @@ class FlowHandler(config_entries.ConfigFlow): async def _create_device(self, host, key=None, password=None): """Create device.""" - # BRP07Cxx devices needs uuid together with key if key: uuid = str(uuid4()) @@ -64,13 +71,25 @@ class FlowHandler(config_entries.ConfigFlow): password=password, ) except asyncio.TimeoutError: - return self.async_abort(reason="device_timeout") + return self.async_show_form( + step_id="user", + data_schema=DATA_SCHEMA, + errors={"base": "device_timeout"}, + ) + except web_exceptions.HTTPForbidden: + return self.async_show_form( + step_id="user", data_schema=DATA_SCHEMA, errors={"base": "forbidden"}, + ) except ClientError: _LOGGER.exception("ClientError") - return self.async_abort(reason="device_fail") + return self.async_show_form( + step_id="user", data_schema=DATA_SCHEMA, errors={"base": "device_fail"}, + ) except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected error creating device") - return self.async_abort(reason="device_fail") + return self.async_show_form( + step_id="user", data_schema=DATA_SCHEMA, errors={"base": "device_fail"}, + ) mac = device.mac return self._create_entry(host, mac, key, uuid, password) @@ -78,16 +97,7 @@ class FlowHandler(config_entries.ConfigFlow): async def async_step_user(self, user_input=None): """User initiated config flow.""" if user_input is None: - return self.async_show_form( - step_id="user", - data_schema=vol.Schema( - { - vol.Required(CONF_HOST): str, - vol.Optional(CONF_KEY): str, - vol.Optional(CONF_PASSWORD): str, - } - ), - ) + return self.async_show_form(step_id="user", data_schema=DATA_SCHEMA,) return await self._create_device( user_input[CONF_HOST], user_input.get(CONF_KEY), diff --git a/homeassistant/components/daikin/manifest.json b/homeassistant/components/daikin/manifest.json index ec993ed9b13..c554e882b48 100644 --- a/homeassistant/components/daikin/manifest.json +++ b/homeassistant/components/daikin/manifest.json @@ -3,7 +3,7 @@ "name": "Daikin AC", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/daikin", - "requirements": ["pydaikin==2.0.0"], + "requirements": ["pydaikin==2.0.1"], "codeowners": ["@fredrike"], "quality_scale": "platinum" } diff --git a/homeassistant/components/daikin/strings.json b/homeassistant/components/daikin/strings.json index 8d2862123d4..0286ca00c32 100644 --- a/homeassistant/components/daikin/strings.json +++ b/homeassistant/components/daikin/strings.json @@ -5,16 +5,19 @@ "title": "Configure Daikin AC", "description": "Enter IP address of your Daikin AC.", "data": { - "host": "Host", - "key": "Authentication key (only used by BRP072C/Zena devices)", - "password": "Device password (only used by SKYFi devices)" - } + "host": "[%key:common::config_flow::data::host%]", + "key": "[%key:common::config_flow::data::api_key%]", + "password": "[%key:common::config_flow::data::password%]" + } } }, "abort": { - "device_timeout": "Timeout connecting to the device.", - "device_fail": "Unexpected error creating device.", - "already_configured": "Device is already configured" + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + }, + "error": { + "device_fail": "[%key:common::config_flow::error::unknown%]", + "forbidden": "[%key:common::config_flow::error::invalid_auth%]", + "device_timeout": "[%key:common::config_flow::error::cannot_connect%]" } } } diff --git a/requirements_all.txt b/requirements_all.txt index 9f4be8a8c7d..d7a0677e566 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1263,7 +1263,7 @@ pycsspeechtts==1.0.3 # pycups==1.9.73 # homeassistant.components.daikin -pydaikin==2.0.0 +pydaikin==2.0.1 # homeassistant.components.danfoss_air pydanfossair==0.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 1cb7ad868cc..734a2f536e0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -533,7 +533,7 @@ pychromecast==5.1.0 pycoolmasternet==0.0.4 # homeassistant.components.daikin -pydaikin==2.0.0 +pydaikin==2.0.1 # homeassistant.components.deconz pydeconz==70 diff --git a/tests/components/daikin/test_config_flow.py b/tests/components/daikin/test_config_flow.py index db2de0bb268..83e13047f80 100644 --- a/tests/components/daikin/test_config_flow.py +++ b/tests/components/daikin/test_config_flow.py @@ -2,12 +2,18 @@ """Tests for the Daikin config flow.""" import asyncio +from aiohttp import ClientError +from aiohttp.web_exceptions import HTTPForbidden import pytest -from homeassistant import data_entry_flow from homeassistant.components.daikin import config_flow from homeassistant.components.daikin.const import KEY_IP, KEY_MAC from homeassistant.const import CONF_HOST +from homeassistant.data_entry_flow import ( + RESULT_TYPE_ABORT, + RESULT_TYPE_CREATE_ENTRY, + RESULT_TYPE_FORM, +) from tests.async_mock import PropertyMock, patch from tests.common import MockConfigEntry @@ -42,11 +48,11 @@ async def test_user(hass, mock_daikin): flow = init_config_flow(hass) result = await flow.async_step_user() - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["type"] == RESULT_TYPE_FORM assert result["step_id"] == "user" result = await flow.async_step_user({CONF_HOST: HOST}) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == HOST assert result["data"][CONF_HOST] == HOST assert result["data"][KEY_MAC] == MAC @@ -58,7 +64,7 @@ async def test_abort_if_already_setup(hass, mock_daikin): MockConfigEntry(domain="daikin", data={KEY_MAC: MAC}).add_to_hass(hass) result = await flow.async_step_user({CONF_HOST: HOST}) - assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" @@ -67,11 +73,11 @@ async def test_import(hass, mock_daikin): flow = init_config_flow(hass) result = await flow.async_step_import({}) - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["type"] == RESULT_TYPE_FORM assert result["step_id"] == "user" result = await flow.async_step_import({CONF_HOST: HOST}) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == HOST assert result["data"][CONF_HOST] == HOST assert result["data"][KEY_MAC] == MAC @@ -82,7 +88,7 @@ async def test_discovery(hass, mock_daikin): flow = init_config_flow(hass) result = await flow.async_step_discovery({KEY_IP: HOST, KEY_MAC: MAC}) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["title"] == HOST assert result["data"][CONF_HOST] == HOST assert result["data"][KEY_MAC] == MAC @@ -90,7 +96,12 @@ async def test_discovery(hass, mock_daikin): @pytest.mark.parametrize( "s_effect,reason", - [(asyncio.TimeoutError, "device_timeout"), (Exception, "device_fail")], + [ + (asyncio.TimeoutError, "device_timeout"), + (HTTPForbidden, "forbidden"), + (ClientError, "device_fail"), + (Exception, "device_fail"), + ], ) async def test_device_abort(hass, mock_daikin, s_effect, reason): """Test device abort.""" @@ -98,5 +109,6 @@ async def test_device_abort(hass, mock_daikin, s_effect, reason): mock_daikin.factory.side_effect = s_effect result = await flow.async_step_user({CONF_HOST: HOST}) - assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT - assert result["reason"] == reason + assert result["type"] == RESULT_TYPE_FORM + assert result["errors"] == {"base": reason} + assert result["step_id"] == "user"