diff --git a/homeassistant/components/apsystems/__init__.py b/homeassistant/components/apsystems/__init__.py index 2df267dda0b..40e62a32475 100644 --- a/homeassistant/components/apsystems/__init__.py +++ b/homeassistant/components/apsystems/__init__.py @@ -7,9 +7,10 @@ from dataclasses import dataclass from APsystemsEZ1 import APsystemsEZ1M from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_IP_ADDRESS, Platform +from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT, Platform from homeassistant.core import HomeAssistant +from .const import DEFAULT_PORT from .coordinator import ApSystemsDataCoordinator PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR] @@ -28,7 +29,11 @@ type ApSystemsConfigEntry = ConfigEntry[ApSystemsData] async def async_setup_entry(hass: HomeAssistant, entry: ApSystemsConfigEntry) -> bool: """Set up this integration using UI.""" - api = APsystemsEZ1M(ip_address=entry.data[CONF_IP_ADDRESS], timeout=8) + api = APsystemsEZ1M( + ip_address=entry.data[CONF_IP_ADDRESS], + port=entry.data.get(CONF_PORT, DEFAULT_PORT), + timeout=8, + ) coordinator = ApSystemsDataCoordinator(hass, api) await coordinator.async_config_entry_first_refresh() assert entry.unique_id diff --git a/homeassistant/components/apsystems/config_flow.py b/homeassistant/components/apsystems/config_flow.py index f49237ce450..5f2f1393aa0 100644 --- a/homeassistant/components/apsystems/config_flow.py +++ b/homeassistant/components/apsystems/config_flow.py @@ -7,14 +7,16 @@ from APsystemsEZ1 import APsystemsEZ1M import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult -from homeassistant.const import CONF_IP_ADDRESS +from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT from homeassistant.helpers.aiohttp_client import async_get_clientsession +import homeassistant.helpers.config_validation as cv -from .const import DOMAIN +from .const import DEFAULT_PORT, DOMAIN DATA_SCHEMA = vol.Schema( { - vol.Required(CONF_IP_ADDRESS): str, + vol.Required(CONF_IP_ADDRESS): cv.string, + vol.Optional(CONF_PORT): cv.port, } ) @@ -32,7 +34,11 @@ class APsystemsLocalAPIFlow(ConfigFlow, domain=DOMAIN): if user_input is not None: session = async_get_clientsession(self.hass, False) - api = APsystemsEZ1M(user_input[CONF_IP_ADDRESS], session=session) + api = APsystemsEZ1M( + ip_address=user_input[CONF_IP_ADDRESS], + port=user_input.get(CONF_PORT, DEFAULT_PORT), + session=session, + ) try: device_info = await api.get_device_info() except (TimeoutError, ClientConnectionError): diff --git a/homeassistant/components/apsystems/const.py b/homeassistant/components/apsystems/const.py index 857652aeae8..4edf0f4122a 100644 --- a/homeassistant/components/apsystems/const.py +++ b/homeassistant/components/apsystems/const.py @@ -4,3 +4,4 @@ from logging import Logger, getLogger LOGGER: Logger = getLogger(__package__) DOMAIN = "apsystems" +DEFAULT_PORT = 8050 diff --git a/homeassistant/components/apsystems/strings.json b/homeassistant/components/apsystems/strings.json index cfd24675311..95499e96b4d 100644 --- a/homeassistant/components/apsystems/strings.json +++ b/homeassistant/components/apsystems/strings.json @@ -3,7 +3,11 @@ "step": { "user": { "data": { - "ip_address": "[%key:common::config_flow::data::ip%]" + "ip_address": "[%key:common::config_flow::data::ip%]", + "port": "[%key:common::config_flow::data::port%]" + }, + "data_description": { + "port": "The integration will default to 8050, if not set, which should be suitable for most installs" } } }, diff --git a/tests/components/apsystems/test_config_flow.py b/tests/components/apsystems/test_config_flow.py index e3fcdf67dcc..3d78524a529 100644 --- a/tests/components/apsystems/test_config_flow.py +++ b/tests/components/apsystems/test_config_flow.py @@ -4,7 +4,7 @@ from unittest.mock import AsyncMock from homeassistant.components.apsystems.const import DOMAIN from homeassistant.config_entries import SOURCE_USER -from homeassistant.const import CONF_IP_ADDRESS +from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType @@ -27,6 +27,24 @@ async def test_form_create_success( assert result["data"].get(CONF_IP_ADDRESS) == "127.0.0.1" +async def test_form_create_success_custom_port( + hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_apsystems: AsyncMock +) -> None: + """Test we handle creating with custom port with success.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={ + CONF_IP_ADDRESS: "127.0.0.1", + CONF_PORT: 8042, + }, + ) + assert result["result"].unique_id == "MY_SERIAL_NUMBER" + assert result.get("type") is FlowResultType.CREATE_ENTRY + assert result["data"].get(CONF_IP_ADDRESS) == "127.0.0.1" + assert result["data"].get(CONF_PORT) == 8042 + + async def test_form_cannot_connect_and_recover( hass: HomeAssistant, mock_apsystems: AsyncMock, mock_setup_entry: AsyncMock ) -> None: @@ -57,6 +75,33 @@ async def test_form_cannot_connect_and_recover( assert result2["data"].get(CONF_IP_ADDRESS) == "127.0.0.1" +async def test_form_cannot_connect_and_recover_custom_port( + hass: HomeAssistant, mock_apsystems: AsyncMock, mock_setup_entry: AsyncMock +) -> None: + """Test we handle cannot connect error but recovering with custom port.""" + + mock_apsystems.get_device_info.side_effect = TimeoutError + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_IP_ADDRESS: "127.0.0.2", CONF_PORT: 8042}, + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": "cannot_connect"} + + mock_apsystems.get_device_info.side_effect = None + + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_IP_ADDRESS: "127.0.0.1", CONF_PORT: 8042}, + ) + assert result2["result"].unique_id == "MY_SERIAL_NUMBER" + assert result2.get("type") is FlowResultType.CREATE_ENTRY + assert result2["data"].get(CONF_IP_ADDRESS) == "127.0.0.1" + assert result2["data"].get(CONF_PORT) == 8042 + + async def test_form_unique_id_already_configured( hass: HomeAssistant, mock_setup_entry: AsyncMock,