From 5dc0bedbc4c71ed51308b9c4c1bab88846ec7831 Mon Sep 17 00:00:00 2001 From: Petar Petrov Date: Tue, 29 Oct 2024 16:28:54 +0200 Subject: [PATCH] Allow fetching HA url to display it in the network settings (#128432) * Allow fetching HA url to display it in the network settings * add tests * use a constant for the url types * just return all url types * Prefer callback without await --------- Co-authored-by: Martin Hjelmare --- homeassistant/components/network/websocket.py | 40 +++++++++++++++++++ tests/components/network/test_init.py | 39 ++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/homeassistant/components/network/websocket.py b/homeassistant/components/network/websocket.py index b97bd2d58d1..22f7dc23f1e 100644 --- a/homeassistant/components/network/websocket.py +++ b/homeassistant/components/network/websocket.py @@ -2,6 +2,7 @@ from __future__ import annotations +from contextlib import suppress from typing import Any import voluptuous as vol @@ -9,6 +10,7 @@ import voluptuous as vol from homeassistant.components import websocket_api from homeassistant.components.websocket_api import ActiveConnection from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.network import NoURLAvailableError, get_url from .const import ATTR_ADAPTERS, ATTR_CONFIGURED_ADAPTERS, NETWORK_CONFIG_SCHEMA from .network import async_get_network @@ -19,6 +21,7 @@ def async_register_websocket_commands(hass: HomeAssistant) -> None: """Register network websocket commands.""" websocket_api.async_register_command(hass, websocket_network_adapters) websocket_api.async_register_command(hass, websocket_network_adapters_configure) + websocket_api.async_register_command(hass, websocket_network_url) @websocket_api.require_admin @@ -62,3 +65,40 @@ async def websocket_network_adapters_configure( msg["id"], {ATTR_CONFIGURED_ADAPTERS: network.configured_adapters}, ) + + +@callback +@websocket_api.require_admin +@websocket_api.websocket_command( + { + vol.Required("type"): "network/url", + } +) +def websocket_network_url( + hass: HomeAssistant, + connection: ActiveConnection, + msg: dict[str, Any], +) -> None: + """Get the internal, external, and cloud URLs.""" + internal_url = None + external_url = None + cloud_url = None + with suppress(NoURLAvailableError): + internal_url = get_url( + hass, allow_internal=True, allow_external=False, allow_cloud=False + ) + with suppress(NoURLAvailableError): + external_url = get_url( + hass, allow_internal=False, allow_external=True, prefer_external=True + ) + with suppress(NoURLAvailableError): + cloud_url = get_url(hass, allow_internal=False, require_cloud=True) + + connection.send_result( + msg["id"], + { + "internal": internal_url, + "external": external_url, + "cloud": cloud_url, + }, + ) diff --git a/tests/components/network/test_init.py b/tests/components/network/test_init.py index 57a12868d0a..dca31106dba 100644 --- a/tests/components/network/test_init.py +++ b/tests/components/network/test_init.py @@ -886,3 +886,42 @@ async def test_async_get_announce_addresses_no_source_ip(hass: HomeAssistant) -> "172.16.1.5", "fe80::dead:beef:dead:beef", ] + + +async def test_websocket_network_url( + hass: HomeAssistant, hass_ws_client: WebSocketGenerator +) -> None: + """Test the network/url websocket command.""" + assert await async_setup_component(hass, "network", {}) + + client = await hass_ws_client(hass) + + with ( + patch( + "homeassistant.helpers.network._get_internal_url", return_value="internal" + ), + patch("homeassistant.helpers.network._get_cloud_url", return_value="cloud"), + ): + await client.send_json({"id": 1, "type": "network/url"}) + msg = await client.receive_json() + assert msg["success"] + assert msg["result"] == { + "internal": "internal", + "external": "cloud", + "cloud": "cloud", + } + + # Test with no cloud URL + with ( + patch( + "homeassistant.helpers.network._get_internal_url", return_value="internal" + ), + ): + await client.send_json({"id": 2, "type": "network/url"}) + msg = await client.receive_json() + assert msg["success"] + assert msg["result"] == { + "internal": "internal", + "external": None, + "cloud": None, + }