diff --git a/homeassistant/components/fully_kiosk/config_flow.py b/homeassistant/components/fully_kiosk/config_flow.py index 7d744214d93..4f9dadd6901 100644 --- a/homeassistant/components/fully_kiosk/config_flow.py +++ b/homeassistant/components/fully_kiosk/config_flow.py @@ -12,7 +12,13 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.components.dhcp import DhcpServiceInfo -from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD +from homeassistant.const import ( + CONF_HOST, + CONF_MAC, + CONF_PASSWORD, + CONF_SSL, + CONF_VERIFY_SSL, +) from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.device_registry import format_mac @@ -31,13 +37,19 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self._discovered_device_info: dict[str, Any] = {} async def _create_entry( - self, host: str, user_input: dict[str, Any], errors: dict[str, str] + self, + host: str, + user_input: dict[str, Any], + errors: dict[str, str], + description_placeholders: dict[str, str] | Any = None, ) -> FlowResult | None: fully = FullyKiosk( async_get_clientsession(self.hass), host, DEFAULT_PORT, user_input[CONF_PASSWORD], + use_ssl=user_input[CONF_SSL], + verify_ssl=user_input[CONF_VERIFY_SSL], ) try: @@ -50,10 +62,12 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) as error: LOGGER.debug(error.args, exc_info=True) errors["base"] = "cannot_connect" + description_placeholders["error_detail"] = str(error.args) return None except Exception as error: # pylint: disable=broad-except LOGGER.exception("Unexpected exception: %s", error) errors["base"] = "unknown" + description_placeholders["error_detail"] = str(error.args) return None await self.async_set_unique_id(device_info["deviceID"], raise_on_progress=False) @@ -64,6 +78,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): CONF_HOST: host, CONF_PASSWORD: user_input[CONF_PASSWORD], CONF_MAC: format_mac(device_info["Mac"]), + CONF_SSL: user_input[CONF_SSL], + CONF_VERIFY_SSL: user_input[CONF_VERIFY_SSL], }, ) @@ -72,8 +88,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) -> FlowResult: """Handle the initial step.""" errors: dict[str, str] = {} + placeholders: dict[str, str] = {} if user_input is not None: - result = await self._create_entry(user_input[CONF_HOST], user_input, errors) + result = await self._create_entry( + user_input[CONF_HOST], user_input, errors, placeholders + ) if result: return result @@ -83,8 +102,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): { vol.Required(CONF_HOST): str, vol.Required(CONF_PASSWORD): str, + vol.Optional(CONF_SSL, default=False): bool, + vol.Optional(CONF_VERIFY_SSL, default=False): bool, } ), + description_placeholders=placeholders, errors=errors, ) @@ -127,6 +149,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): data_schema=vol.Schema( { vol.Required(CONF_PASSWORD): str, + vol.Optional(CONF_SSL, default=False): bool, + vol.Optional(CONF_VERIFY_SSL, default=False): bool, } ), description_placeholders=placeholders, diff --git a/homeassistant/components/fully_kiosk/coordinator.py b/homeassistant/components/fully_kiosk/coordinator.py index 0cfc15268b4..17facb79dbb 100644 --- a/homeassistant/components/fully_kiosk/coordinator.py +++ b/homeassistant/components/fully_kiosk/coordinator.py @@ -6,7 +6,7 @@ from fullykiosk import FullyKiosk from fullykiosk.exceptions import FullyKioskError from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_PASSWORD +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_SSL, CONF_VERIFY_SSL from homeassistant.core import HomeAssistant from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -24,6 +24,8 @@ class FullyKioskDataUpdateCoordinator(DataUpdateCoordinator): entry.data[CONF_HOST], DEFAULT_PORT, entry.data[CONF_PASSWORD], + use_ssl=entry.data[CONF_SSL], + verify_ssl=entry.data[CONF_VERIFY_SSL], ) super().__init__( hass, @@ -31,6 +33,7 @@ class FullyKioskDataUpdateCoordinator(DataUpdateCoordinator): name=entry.data[CONF_HOST], update_interval=UPDATE_INTERVAL, ) + self.use_ssl = entry.data[CONF_SSL] async def _async_update_data(self) -> dict[str, Any]: """Update data via library.""" diff --git a/homeassistant/components/fully_kiosk/entity.py b/homeassistant/components/fully_kiosk/entity.py index fcb6f35eb11..87c441dd545 100644 --- a/homeassistant/components/fully_kiosk/entity.py +++ b/homeassistant/components/fully_kiosk/entity.py @@ -1,6 +1,8 @@ """Base entity for the Fully Kiosk Browser integration.""" from __future__ import annotations +from yarl import URL + from homeassistant.const import ATTR_CONNECTIONS from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity import Entity @@ -30,13 +32,20 @@ class FullyKioskEntity(CoordinatorEntity[FullyKioskDataUpdateCoordinator], Entit def __init__(self, coordinator: FullyKioskDataUpdateCoordinator) -> None: """Initialize the Fully Kiosk Browser entity.""" super().__init__(coordinator=coordinator) + + url = URL.build( + scheme="https" if coordinator.use_ssl else "http", + host=coordinator.data["ip4"], + port=2323, + ) + device_info = DeviceInfo( identifiers={(DOMAIN, coordinator.data["deviceID"])}, name=coordinator.data["deviceName"], manufacturer=coordinator.data["deviceManufacturer"], model=coordinator.data["deviceModel"], sw_version=coordinator.data["appVersionName"], - configuration_url=f"http://{coordinator.data['ip4']}:2323", + configuration_url=str(url), ) if "Mac" in coordinator.data and valid_global_mac_address( coordinator.data["Mac"] diff --git a/homeassistant/components/fully_kiosk/strings.json b/homeassistant/components/fully_kiosk/strings.json index d61e8a7b7a8..bf46feeec3f 100644 --- a/homeassistant/components/fully_kiosk/strings.json +++ b/homeassistant/components/fully_kiosk/strings.json @@ -10,13 +10,15 @@ "user": { "data": { "host": "[%key:common::config_flow::data::host%]", - "password": "[%key:common::config_flow::data::password%]" + "password": "[%key:common::config_flow::data::password%]", + "ssl": "[%key:common::config_flow::data::ssl%]", + "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]" } } }, "error": { - "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", - "unknown": "[%key:common::config_flow::error::unknown%]" + "cannot_connect": "Cannot connect. Details: {error_detail}", + "unknown": "Unknown. Details: {error_detail}" }, "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_account%]" diff --git a/tests/components/fully_kiosk/conftest.py b/tests/components/fully_kiosk/conftest.py index bed08b532fd..e409a0a3787 100644 --- a/tests/components/fully_kiosk/conftest.py +++ b/tests/components/fully_kiosk/conftest.py @@ -8,7 +8,13 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest from homeassistant.components.fully_kiosk.const import DOMAIN -from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD +from homeassistant.const import ( + CONF_HOST, + CONF_MAC, + CONF_PASSWORD, + CONF_SSL, + CONF_VERIFY_SSL, +) from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry, load_fixture @@ -24,6 +30,8 @@ def mock_config_entry() -> MockConfigEntry: CONF_HOST: "127.0.0.1", CONF_PASSWORD: "mocked-password", CONF_MAC: "aa:bb:cc:dd:ee:ff", + CONF_SSL: False, + CONF_VERIFY_SSL: False, }, unique_id="12345", ) diff --git a/tests/components/fully_kiosk/test_config_flow.py b/tests/components/fully_kiosk/test_config_flow.py index 566f3b6d292..018a62b5dc7 100644 --- a/tests/components/fully_kiosk/test_config_flow.py +++ b/tests/components/fully_kiosk/test_config_flow.py @@ -10,7 +10,13 @@ import pytest from homeassistant.components.dhcp import DhcpServiceInfo from homeassistant.components.fully_kiosk.const import DOMAIN from homeassistant.config_entries import SOURCE_DHCP, SOURCE_MQTT, SOURCE_USER -from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD +from homeassistant.const import ( + CONF_HOST, + CONF_MAC, + CONF_PASSWORD, + CONF_SSL, + CONF_VERIFY_SSL, +) from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers.service_info.mqtt import MqttServiceInfo @@ -35,6 +41,8 @@ async def test_user_flow( { CONF_HOST: "1.1.1.1", CONF_PASSWORD: "test-password", + CONF_SSL: False, + CONF_VERIFY_SSL: False, }, ) @@ -44,6 +52,8 @@ async def test_user_flow( CONF_HOST: "1.1.1.1", CONF_PASSWORD: "test-password", CONF_MAC: "aa:bb:cc:dd:ee:ff", + CONF_SSL: False, + CONF_VERIFY_SSL: False, } assert "result" in result2 assert result2["result"].unique_id == "12345" @@ -76,7 +86,13 @@ async def test_errors( mock_fully_kiosk_config_flow.getDeviceInfo.side_effect = side_effect result2 = await hass.config_entries.flow.async_configure( - flow_id, user_input={CONF_HOST: "1.1.1.1", CONF_PASSWORD: "test-password"} + flow_id, + user_input={ + CONF_HOST: "1.1.1.1", + CONF_PASSWORD: "test-password", + CONF_SSL: False, + CONF_VERIFY_SSL: False, + }, ) assert result2.get("type") == FlowResultType.FORM @@ -88,7 +104,13 @@ async def test_errors( mock_fully_kiosk_config_flow.getDeviceInfo.side_effect = None result3 = await hass.config_entries.flow.async_configure( - flow_id, user_input={CONF_HOST: "1.1.1.1", CONF_PASSWORD: "test-password"} + flow_id, + user_input={ + CONF_HOST: "1.1.1.1", + CONF_PASSWORD: "test-password", + CONF_SSL: True, + CONF_VERIFY_SSL: False, + }, ) assert result3.get("type") == FlowResultType.CREATE_ENTRY @@ -97,6 +119,8 @@ async def test_errors( CONF_HOST: "1.1.1.1", CONF_PASSWORD: "test-password", CONF_MAC: "aa:bb:cc:dd:ee:ff", + CONF_SSL: True, + CONF_VERIFY_SSL: False, } assert "result" in result3 assert result3["result"].unique_id == "12345" @@ -124,6 +148,8 @@ async def test_duplicate_updates_existing_entry( { CONF_HOST: "1.1.1.1", CONF_PASSWORD: "test-password", + CONF_SSL: True, + CONF_VERIFY_SSL: True, }, ) @@ -133,6 +159,8 @@ async def test_duplicate_updates_existing_entry( CONF_HOST: "1.1.1.1", CONF_PASSWORD: "test-password", CONF_MAC: "aa:bb:cc:dd:ee:ff", + CONF_SSL: True, + CONF_VERIFY_SSL: True, } assert len(mock_fully_kiosk_config_flow.getDeviceInfo.mock_calls) == 1 @@ -161,6 +189,8 @@ async def test_dhcp_discovery_updates_entry( CONF_HOST: "127.0.0.2", CONF_PASSWORD: "mocked-password", CONF_MAC: "aa:bb:cc:dd:ee:ff", + CONF_SSL: False, + CONF_VERIFY_SSL: False, } @@ -212,6 +242,8 @@ async def test_mqtt_discovery_flow( result["flow_id"], { CONF_PASSWORD: "test-password", + CONF_SSL: False, + CONF_VERIFY_SSL: False, }, ) @@ -222,6 +254,8 @@ async def test_mqtt_discovery_flow( CONF_HOST: "192.168.1.234", CONF_PASSWORD: "test-password", CONF_MAC: "aa:bb:cc:dd:ee:ff", + CONF_SSL: False, + CONF_VERIFY_SSL: False, } assert "result" in confirmResult assert confirmResult["result"].unique_id == "12345" diff --git a/tests/components/fully_kiosk/test_init.py b/tests/components/fully_kiosk/test_init.py index 5c77b8a9d06..2e77cdb2f1d 100644 --- a/tests/components/fully_kiosk/test_init.py +++ b/tests/components/fully_kiosk/test_init.py @@ -9,7 +9,13 @@ import pytest from homeassistant.components.fully_kiosk.const import DOMAIN from homeassistant.components.fully_kiosk.entity import valid_global_mac_address from homeassistant.config_entries import ConfigEntryState -from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PASSWORD +from homeassistant.const import ( + CONF_HOST, + CONF_MAC, + CONF_PASSWORD, + CONF_SSL, + CONF_VERIFY_SSL, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er @@ -92,6 +98,8 @@ async def test_multiple_kiosk_with_empty_mac( CONF_HOST: "127.0.0.1", CONF_PASSWORD: "mocked-password", CONF_MAC: "", + CONF_SSL: False, + CONF_VERIFY_SSL: False, }, unique_id="111111", ) @@ -105,6 +113,8 @@ async def test_multiple_kiosk_with_empty_mac( CONF_HOST: "127.0.0.2", CONF_PASSWORD: "mocked-password", CONF_MAC: "", + CONF_SSL: True, + CONF_VERIFY_SSL: False, }, unique_id="22222", )