Fix configuration_url for Shelly device using IPv6 (#121939)

Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com>
This commit is contained in:
Maciej Bieniek 2024-07-15 08:31:44 +02:00 committed by GitHub
parent 9f53d0ccd9
commit 50751574b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 2 deletions

View file

@ -61,6 +61,7 @@ from .utils import (
async_create_issue_unsupported_firmware, async_create_issue_unsupported_firmware,
get_block_device_sleep_period, get_block_device_sleep_period,
get_device_entry_gen, get_device_entry_gen,
get_host,
get_http_port, get_http_port,
get_rpc_device_wakeup_period, get_rpc_device_wakeup_period,
update_device_fw_info, update_device_fw_info,
@ -147,7 +148,7 @@ class ShellyCoordinatorBase[_DeviceT: BlockDevice | RpcDevice](
model=MODEL_NAMES.get(self.model, self.model), model=MODEL_NAMES.get(self.model, self.model),
sw_version=self.sw_version, sw_version=self.sw_version,
hw_version=f"gen{get_device_entry_gen(self.entry)} ({self.model})", hw_version=f"gen{get_device_entry_gen(self.entry)} ({self.model})",
configuration_url=f"http://{self.entry.data[CONF_HOST]}:{get_http_port(self.entry.data)}", configuration_url=f"http://{get_host(self.entry.data[CONF_HOST])}:{get_http_port(self.entry.data)}",
) )
self.device_id = device_entry.id self.device_id = device_entry.id

View file

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime, timedelta
from ipaddress import IPv4Address from ipaddress import IPv4Address, IPv6Address, ip_address
import re import re
from types import MappingProxyType from types import MappingProxyType
from typing import Any, cast from typing import Any, cast
@ -486,6 +486,20 @@ def get_http_port(data: MappingProxyType[str, Any]) -> int:
return cast(int, data.get(CONF_PORT, DEFAULT_HTTP_PORT)) return cast(int, data.get(CONF_PORT, DEFAULT_HTTP_PORT))
def get_host(host: str) -> str:
"""Get the device IP address or hostname."""
try:
ip_object = ip_address(host)
except ValueError:
# host contains hostname
return host
if isinstance(ip_object, IPv6Address):
return f"[{host}]"
return host
@callback @callback
def async_remove_shelly_rpc_entities( def async_remove_shelly_rpc_entities(
hass: HomeAssistant, domain: str, mac: str, keys: list[str] hass: HomeAssistant, domain: str, mac: str, keys: list[str]

View file

@ -23,6 +23,7 @@ from homeassistant.components.shelly.utils import (
get_block_device_sleep_period, get_block_device_sleep_period,
get_block_input_triggers, get_block_input_triggers,
get_device_uptime, get_device_uptime,
get_host,
get_number_of_channels, get_number_of_channels,
get_release_url, get_release_url,
get_rpc_channel_name, get_rpc_channel_name,
@ -274,3 +275,19 @@ def test_get_release_url(
result = get_release_url(gen, model, beta) result = get_release_url(gen, model, beta)
assert result is expected assert result is expected
@pytest.mark.parametrize(
("host", "expected"),
[
("shelly_device.local", "shelly_device.local"),
("192.168.178.12", "192.168.178.12"),
(
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]",
),
],
)
def test_get_host(host: str, expected: str) -> None:
"""Test get_host function."""
assert get_host(host) == expected