Randomize thread network names (#108302)
* Randomize thread network names * Use PAN ID as network name suffix * Apply suggestions from code review Co-authored-by: Stefan Agner <stefan@agner.ch> * Update tests * Format code * Change format of network name again --------- Co-authored-by: Stefan Agner <stefan@agner.ch>
This commit is contained in:
parent
d8f16c14ab
commit
823f268054
5 changed files with 47 additions and 9 deletions
|
@ -28,7 +28,11 @@ from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
from .const import DEFAULT_CHANNEL, DOMAIN
|
from .const import DEFAULT_CHANNEL, DOMAIN
|
||||||
from .util import get_allowed_channel
|
from .util import (
|
||||||
|
compose_default_network_name,
|
||||||
|
generate_random_pan_id,
|
||||||
|
get_allowed_channel,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -85,10 +89,12 @@ class OTBRConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"not importing TLV with channel %s", thread_dataset_channel
|
"not importing TLV with channel %s", thread_dataset_channel
|
||||||
)
|
)
|
||||||
|
pan_id = generate_random_pan_id()
|
||||||
await api.create_active_dataset(
|
await api.create_active_dataset(
|
||||||
python_otbr_api.ActiveDataSet(
|
python_otbr_api.ActiveDataSet(
|
||||||
channel=allowed_channel if allowed_channel else DEFAULT_CHANNEL,
|
channel=allowed_channel if allowed_channel else DEFAULT_CHANNEL,
|
||||||
network_name="home-assistant",
|
network_name=compose_default_network_name(pan_id),
|
||||||
|
pan_id=pan_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
await api.set_enabled(True)
|
await api.set_enabled(True)
|
||||||
|
|
|
@ -5,6 +5,7 @@ from collections.abc import Callable, Coroutine
|
||||||
import dataclasses
|
import dataclasses
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
from typing import Any, Concatenate, ParamSpec, TypeVar, cast
|
from typing import Any, Concatenate, ParamSpec, TypeVar, cast
|
||||||
|
|
||||||
import python_otbr_api
|
import python_otbr_api
|
||||||
|
@ -48,6 +49,17 @@ INSECURE_PASSPHRASES = (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def compose_default_network_name(pan_id: int) -> str:
|
||||||
|
"""Generate a default network name."""
|
||||||
|
return f"ha-thread-{pan_id:04x}"
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_pan_id() -> int:
|
||||||
|
"""Generate a random PAN ID."""
|
||||||
|
# PAN ID is 2 bytes, 0xffff is reserved for broadcast
|
||||||
|
return random.randint(0, 0xFFFE)
|
||||||
|
|
||||||
|
|
||||||
def _handle_otbr_error(
|
def _handle_otbr_error(
|
||||||
func: Callable[Concatenate[OTBRData, _P], Coroutine[Any, Any, _R]],
|
func: Callable[Concatenate[OTBRData, _P], Coroutine[Any, Any, _R]],
|
||||||
) -> Callable[Concatenate[OTBRData, _P], Coroutine[Any, Any, _R]]:
|
) -> Callable[Concatenate[OTBRData, _P], Coroutine[Any, Any, _R]]:
|
||||||
|
|
|
@ -16,7 +16,13 @@ from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
from .const import DEFAULT_CHANNEL, DOMAIN
|
from .const import DEFAULT_CHANNEL, DOMAIN
|
||||||
from .util import OTBRData, get_allowed_channel, update_issues
|
from .util import (
|
||||||
|
OTBRData,
|
||||||
|
compose_default_network_name,
|
||||||
|
generate_random_pan_id,
|
||||||
|
get_allowed_channel,
|
||||||
|
update_issues,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -99,10 +105,13 @@ async def websocket_create_network(
|
||||||
connection.send_error(msg["id"], "factory_reset_failed", str(exc))
|
connection.send_error(msg["id"], "factory_reset_failed", str(exc))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
pan_id = generate_random_pan_id()
|
||||||
try:
|
try:
|
||||||
await data.create_active_dataset(
|
await data.create_active_dataset(
|
||||||
python_otbr_api.ActiveDataSet(
|
python_otbr_api.ActiveDataSet(
|
||||||
channel=channel, network_name="home-assistant"
|
channel=channel,
|
||||||
|
network_name=compose_default_network_name(pan_id),
|
||||||
|
pan_id=pan_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except HomeAssistantError as exc:
|
except HomeAssistantError as exc:
|
||||||
|
|
|
@ -121,9 +121,11 @@ async def test_user_flow_router_not_setup(
|
||||||
# Check we create a dataset and enable the router
|
# Check we create a dataset and enable the router
|
||||||
assert aioclient_mock.mock_calls[-2][0] == "PUT"
|
assert aioclient_mock.mock_calls[-2][0] == "PUT"
|
||||||
assert aioclient_mock.mock_calls[-2][1].path == "/node/dataset/active"
|
assert aioclient_mock.mock_calls[-2][1].path == "/node/dataset/active"
|
||||||
|
pan_id = aioclient_mock.mock_calls[-2][2]["PanId"]
|
||||||
assert aioclient_mock.mock_calls[-2][2] == {
|
assert aioclient_mock.mock_calls[-2][2] == {
|
||||||
"Channel": 15,
|
"Channel": 15,
|
||||||
"NetworkName": "home-assistant",
|
"NetworkName": f"ha-thread-{pan_id:04x}",
|
||||||
|
"PanId": pan_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert aioclient_mock.mock_calls[-1][0] == "PUT"
|
assert aioclient_mock.mock_calls[-1][0] == "PUT"
|
||||||
|
@ -425,9 +427,11 @@ async def test_hassio_discovery_flow_router_not_setup(
|
||||||
# Check we create a dataset and enable the router
|
# Check we create a dataset and enable the router
|
||||||
assert aioclient_mock.mock_calls[-2][0] == "PUT"
|
assert aioclient_mock.mock_calls[-2][0] == "PUT"
|
||||||
assert aioclient_mock.mock_calls[-2][1].path == "/node/dataset/active"
|
assert aioclient_mock.mock_calls[-2][1].path == "/node/dataset/active"
|
||||||
|
pan_id = aioclient_mock.mock_calls[-2][2]["PanId"]
|
||||||
assert aioclient_mock.mock_calls[-2][2] == {
|
assert aioclient_mock.mock_calls[-2][2] == {
|
||||||
"Channel": 15,
|
"Channel": 15,
|
||||||
"NetworkName": "home-assistant",
|
"NetworkName": f"ha-thread-{pan_id:04x}",
|
||||||
|
"PanId": pan_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert aioclient_mock.mock_calls[-1][0] == "PUT"
|
assert aioclient_mock.mock_calls[-1][0] == "PUT"
|
||||||
|
@ -532,9 +536,11 @@ async def test_hassio_discovery_flow_router_not_setup_has_preferred_2(
|
||||||
# Check we create a dataset and enable the router
|
# Check we create a dataset and enable the router
|
||||||
assert aioclient_mock.mock_calls[-2][0] == "PUT"
|
assert aioclient_mock.mock_calls[-2][0] == "PUT"
|
||||||
assert aioclient_mock.mock_calls[-2][1].path == "/node/dataset/active"
|
assert aioclient_mock.mock_calls[-2][1].path == "/node/dataset/active"
|
||||||
|
pan_id = aioclient_mock.mock_calls[-2][2]["PanId"]
|
||||||
assert aioclient_mock.mock_calls[-2][2] == {
|
assert aioclient_mock.mock_calls[-2][2] == {
|
||||||
"Channel": 15,
|
"Channel": 15,
|
||||||
"NetworkName": "home-assistant",
|
"NetworkName": f"ha-thread-{pan_id:04x}",
|
||||||
|
"PanId": pan_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert aioclient_mock.mock_calls[-1][0] == "PUT"
|
assert aioclient_mock.mock_calls[-1][0] == "PUT"
|
||||||
|
|
|
@ -105,7 +105,10 @@ async def test_create_network(
|
||||||
"python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=DATASET_CH16
|
"python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=DATASET_CH16
|
||||||
) as get_active_dataset_tlvs_mock, patch(
|
) as get_active_dataset_tlvs_mock, patch(
|
||||||
"homeassistant.components.thread.dataset_store.DatasetStore.async_add"
|
"homeassistant.components.thread.dataset_store.DatasetStore.async_add"
|
||||||
) as mock_add:
|
) as mock_add, patch(
|
||||||
|
"homeassistant.components.otbr.util.random.randint",
|
||||||
|
return_value=0x1234,
|
||||||
|
):
|
||||||
await websocket_client.send_json_auto_id({"type": "otbr/create_network"})
|
await websocket_client.send_json_auto_id({"type": "otbr/create_network"})
|
||||||
|
|
||||||
msg = await websocket_client.receive_json()
|
msg = await websocket_client.receive_json()
|
||||||
|
@ -113,7 +116,9 @@ async def test_create_network(
|
||||||
assert msg["result"] is None
|
assert msg["result"] is None
|
||||||
|
|
||||||
create_dataset_mock.assert_called_once_with(
|
create_dataset_mock.assert_called_once_with(
|
||||||
python_otbr_api.models.ActiveDataSet(channel=15, network_name="home-assistant")
|
python_otbr_api.models.ActiveDataSet(
|
||||||
|
channel=15, network_name="ha-thread-1234", pan_id=0x1234
|
||||||
|
)
|
||||||
)
|
)
|
||||||
factory_reset_mock.assert_called_once_with()
|
factory_reset_mock.assert_called_once_with()
|
||||||
assert len(set_enabled_mock.mock_calls) == 2
|
assert len(set_enabled_mock.mock_calls) == 2
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue