diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index 0e55c3e715c..f7986f91540 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -10,7 +10,7 @@ import async_timeout import voluptuous as vol from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_SCAN_INTERVAL +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import device_registry as dr @@ -21,7 +21,13 @@ from homeassistant.helpers.update_coordinator import ( UpdateFailed, ) -from .const import COORDINATOR, DEFAULT_SCAN_INTERVAL, DOMAIN, UNDO_UPDATE_LISTENER +from .const import ( + COORDINATOR, + DEFAULT_PORT, + DEFAULT_SCAN_INTERVAL, + DOMAIN, + UNDO_UPDATE_LISTENER, +) CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA) @@ -39,9 +45,12 @@ async def async_setup(hass: HomeAssistant, config: dict): async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Plugwise Smiles from a config entry.""" websession = async_get_clientsession(hass, verify_ssl=False) + api = Smile( host=entry.data[CONF_HOST], password=entry.data[CONF_PASSWORD], + port=entry.data.get(CONF_PORT, DEFAULT_PORT), + timeout=30, websession=websession, ) diff --git a/homeassistant/components/plugwise/config_flow.py b/homeassistant/components/plugwise/config_flow.py index 689bfb68f22..14405062231 100644 --- a/homeassistant/components/plugwise/config_flow.py +++ b/homeassistant/components/plugwise/config_flow.py @@ -5,12 +5,16 @@ from Plugwise_Smile.Smile import Smile import voluptuous as vol from homeassistant import config_entries, core, exceptions -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_SCAN_INTERVAL +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL from homeassistant.core import callback from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import DiscoveryInfoType -from .const import DEFAULT_SCAN_INTERVAL, DOMAIN # pylint:disable=unused-import +from .const import ( # pylint:disable=unused-import + DEFAULT_PORT, + DEFAULT_SCAN_INTERVAL, + DOMAIN, +) _LOGGER = logging.getLogger(__name__) @@ -27,6 +31,7 @@ def _base_schema(discovery_info): if not discovery_info: base_schema[vol.Required(CONF_HOST)] = str + base_schema[vol.Optional(CONF_PORT, default=DEFAULT_PORT)] = int base_schema[vol.Required(CONF_PASSWORD)] = str @@ -40,9 +45,11 @@ async def validate_input(hass: core.HomeAssistant, data): Data has the keys from _base_schema() with values provided by the user. """ websession = async_get_clientsession(hass, verify_ssl=False) + api = Smile( host=data[CONF_HOST], password=data[CONF_PASSWORD], + port=data[CONF_PORT], timeout=30, websession=websession, ) @@ -83,6 +90,7 @@ class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167 self.context["title_placeholders"] = { CONF_HOST: discovery_info[CONF_HOST], + CONF_PORT: discovery_info.get(CONF_PORT, DEFAULT_PORT), "name": _name, } return await self.async_step_user() @@ -95,6 +103,7 @@ class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if self.discovery_info: user_input[CONF_HOST] = self.discovery_info[CONF_HOST] + user_input[CONF_PORT] = self.discovery_info.get(CONF_PORT, DEFAULT_PORT) for entry in self._async_current_entries(): if entry.data.get(CONF_HOST) == user_input[CONF_HOST]: diff --git a/homeassistant/components/plugwise/strings.json b/homeassistant/components/plugwise/strings.json index 7dc8542698b..0abcd780255 100644 --- a/homeassistant/components/plugwise/strings.json +++ b/homeassistant/components/plugwise/strings.json @@ -13,10 +13,11 @@ "step": { "user": { "title": "Connect to the Smile", - "description": "Details", + "description": "Please enter:", "data": { + "password": "Smile ID", "host": "Smile IP address", - "password": "Smile ID" + "port": "Smile port number" } } }, diff --git a/tests/components/plugwise/test_config_flow.py b/tests/components/plugwise/test_config_flow.py index e0f4993df55..9b67f06e469 100644 --- a/tests/components/plugwise/test_config_flow.py +++ b/tests/components/plugwise/test_config_flow.py @@ -3,7 +3,11 @@ from Plugwise_Smile.Smile import Smile import pytest from homeassistant import config_entries, data_entry_flow, setup -from homeassistant.components.plugwise.const import DEFAULT_SCAN_INTERVAL, DOMAIN +from homeassistant.components.plugwise.const import ( + DEFAULT_PORT, + DEFAULT_SCAN_INTERVAL, + DOMAIN, +) from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_SCAN_INTERVAL @@ -13,8 +17,11 @@ from tests.common import MockConfigEntry TEST_HOST = "1.1.1.1" TEST_HOSTNAME = "smileabcdef" TEST_PASSWORD = "test_password" +TEST_PORT = 81 + TEST_DISCOVERY = { "host": TEST_HOST, + "port": DEFAULT_PORT, "hostname": f"{TEST_HOSTNAME}.local.", "server": f"{TEST_HOSTNAME}.local.", "properties": { @@ -68,6 +75,7 @@ async def test_form(hass): assert result2["data"] == { "host": TEST_HOST, "password": TEST_PASSWORD, + "port": DEFAULT_PORT, } assert len(mock_setup.mock_calls) == 1 @@ -106,6 +114,7 @@ async def test_zeroconf_form(hass): assert result2["data"] == { "host": TEST_HOST, "password": TEST_PASSWORD, + "port": DEFAULT_PORT, } assert len(mock_setup.mock_calls) == 1 @@ -176,6 +185,24 @@ async def test_form_cannot_connect(hass, mock_smile): assert result2["errors"] == {"base": "cannot_connect"} +async def test_form_cannot_connect_port(hass, mock_smile): + """Test we handle cannot connect to port error.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + + mock_smile.connect.side_effect = Smile.ConnectionFailedError + mock_smile.gateway_id = "0a636a4fc1704ab4a24e4f7e37fb187a" + + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {"host": TEST_HOST, "password": TEST_PASSWORD, "port": TEST_PORT}, + ) + + assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result2["errors"] == {"base": "cannot_connect"} + + async def test_form_other_problem(hass, mock_smile): """Test we handle cannot connect error.""" result = await hass.config_entries.flow.async_init(