Skip to content

Commit 5b9f737

Browse files
puddlyCopilotfrenck
authored
Allow hardware integrations to specify TX power for ZHA (home-assistant#155855)
Co-authored-by: Copilot <[email protected]> Co-authored-by: Franck Nijhof <[email protected]>
1 parent a4c0a9b commit 5b9f737

File tree

6 files changed

+105
-4
lines changed

6 files changed

+105
-4
lines changed

homeassistant/components/homeassistant_connect_zbt2/config_flow.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
NABU_CASA_FIRMWARE_RELEASES_URL,
4040
PID,
4141
PRODUCT,
42+
RADIO_TX_POWER_DBM_BY_COUNTRY,
43+
RADIO_TX_POWER_DBM_DEFAULT,
4244
SERIAL_NUMBER,
4345
VID,
4446
)
@@ -103,6 +105,21 @@ async def async_step_install_thread_firmware(
103105
next_step_id="finish_thread_installation",
104106
)
105107

108+
def _extra_zha_hardware_options(self) -> dict[str, Any]:
109+
"""Return extra ZHA hardware options."""
110+
country = self.hass.config.country
111+
112+
if country is None:
113+
tx_power = RADIO_TX_POWER_DBM_DEFAULT
114+
else:
115+
tx_power = RADIO_TX_POWER_DBM_BY_COUNTRY.get(
116+
country, RADIO_TX_POWER_DBM_DEFAULT
117+
)
118+
119+
return {
120+
"tx_power": tx_power,
121+
}
122+
106123

107124
class HomeAssistantConnectZBT2ConfigFlow(
108125
ZBT2FirmwareMixin,

homeassistant/components/homeassistant_connect_zbt2/const.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Constants for the Home Assistant Connect ZBT-2 integration."""
22

3+
from homeassistant.generated.countries import COUNTRIES
4+
35
DOMAIN = "homeassistant_connect_zbt2"
46

57
NABU_CASA_FIRMWARE_RELEASES_URL = (
@@ -17,3 +19,59 @@
1719
DEVICE = "device"
1820

1921
HARDWARE_NAME = "Home Assistant Connect ZBT-2"
22+
23+
RADIO_TX_POWER_DBM_DEFAULT = 8
24+
RADIO_TX_POWER_DBM_BY_COUNTRY = {
25+
# EU Member States
26+
"AT": 10,
27+
"BE": 10,
28+
"BG": 10,
29+
"HR": 10,
30+
"CY": 10,
31+
"CZ": 10,
32+
"DK": 10,
33+
"EE": 10,
34+
"FI": 10,
35+
"FR": 10,
36+
"DE": 10,
37+
"GR": 10,
38+
"HU": 10,
39+
"IE": 10,
40+
"IT": 10,
41+
"LV": 10,
42+
"LT": 10,
43+
"LU": 10,
44+
"MT": 10,
45+
"NL": 10,
46+
"PL": 10,
47+
"PT": 10,
48+
"RO": 10,
49+
"SK": 10,
50+
"SI": 10,
51+
"ES": 10,
52+
"SE": 10,
53+
# EEA Members
54+
"IS": 10,
55+
"LI": 10,
56+
"NO": 10,
57+
# Standards harmonized with RED or ETSI
58+
"CH": 10,
59+
"GB": 10,
60+
"TR": 10,
61+
"AL": 10,
62+
"BA": 10,
63+
"GE": 10,
64+
"MD": 10,
65+
"ME": 10,
66+
"MK": 10,
67+
"RS": 10,
68+
"UA": 10,
69+
# Other CEPT nations
70+
"AD": 10,
71+
"AZ": 10,
72+
"MC": 10,
73+
"SM": 10,
74+
"VA": 10,
75+
}
76+
77+
assert set(RADIO_TX_POWER_DBM_BY_COUNTRY) <= COUNTRIES

homeassistant/components/homeassistant_hardware/firmware_config_flow.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,10 @@ async def async_step_pre_confirm_zigbee(
456456
# This step is necessary to prevent `user_input` from being passed through
457457
return await self.async_step_continue_zigbee()
458458

459+
def _extra_zha_hardware_options(self) -> dict[str, Any]:
460+
"""Return extra ZHA hardware options."""
461+
return {}
462+
459463
async def async_step_continue_zigbee(
460464
self, user_input: dict[str, Any] | None = None
461465
) -> ConfigFlowResult:
@@ -478,6 +482,7 @@ async def async_step_continue_zigbee(
478482
},
479483
"radio_type": "ezsp",
480484
"flow_strategy": self._zigbee_flow_strategy,
485+
**self._extra_zha_hardware_options(),
481486
},
482487
)
483488
return self._continue_zha_flow(result)

homeassistant/components/zha/config_flow.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import voluptuous as vol
1515
from zha.application.const import RadioType
1616
import zigpy.backups
17-
from zigpy.config import CONF_DEVICE, CONF_DEVICE_PATH
17+
from zigpy.config import CONF_DEVICE, CONF_DEVICE_PATH, CONF_NWK_TX_POWER
1818
from zigpy.exceptions import CannotWriteNetworkSettings, DestructiveWriteNetworkSettings
1919

2020
from homeassistant.components import onboarding, usb
@@ -191,6 +191,7 @@ def __init__(self) -> None:
191191
self._hass = None # type: ignore[assignment]
192192
self._radio_mgr = ZhaRadioManager()
193193
self._restore_backup_task: asyncio.Task[None] | None = None
194+
self._extra_network_config: dict[str, Any] = {}
194195

195196
@property
196197
def hass(self) -> HomeAssistant:
@@ -622,7 +623,8 @@ async def async_step_form_new_network(
622623
self, user_input: dict[str, Any] | None = None
623624
) -> ConfigFlowResult:
624625
"""Form a brand-new network."""
625-
await self._radio_mgr.async_form_network()
626+
await self._radio_mgr.async_form_network(config=self._extra_network_config)
627+
626628
# Load the newly formed network settings to get the network info
627629
await self._radio_mgr.async_load_network_settings()
628630
return await self._async_create_radio_entry()
@@ -1007,6 +1009,9 @@ async def async_step_hardware(
10071009
device_path = device_settings[CONF_DEVICE_PATH]
10081010
self._flow_strategy = discovery_data.get("flow_strategy")
10091011

1012+
if "tx_power" in discovery_data:
1013+
self._extra_network_config[CONF_NWK_TX_POWER] = discovery_data["tx_power"]
1014+
10101015
await self._set_unique_id_and_update_ignored_flow(
10111016
unique_id=f"{name}_{radio_type.name}_{device_path}",
10121017
device_path=device_path,

homeassistant/components/zha/radio_manager.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
vol.Required("port"): DEVICE_SCHEMA,
7979
vol.Required("radio_type"): str,
8080
vol.Optional("flow_strategy"): vol.All(str, vol.Coerce(ZigbeeFlowStrategy)),
81+
vol.Optional("tx_power"): vol.All(vol.Coerce(int), vol.Range(min=0, max=10)),
8182
}
8283
)
8384

@@ -322,7 +323,7 @@ async def async_load_network_settings(
322323

323324
return backup
324325

325-
async def async_form_network(self) -> None:
326+
async def async_form_network(self, config: dict[str, Any] | None) -> None:
326327
"""Form a brand-new network."""
327328

328329
# When forming a new network, we delete the ZHA database to prevent old devices
@@ -331,7 +332,7 @@ async def async_form_network(self) -> None:
331332
await self.hass.async_add_executor_job(os.remove, self.zigpy_database_path)
332333

333334
async with self.create_zigpy_app() as app:
334-
await app.form_network()
335+
await app.form_network(config=config)
335336

336337
async def async_reset_adapter(self) -> None:
337338
"""Reset the current adapter."""

tests/components/homeassistant_connect_zbt2/test_config_flow.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,23 @@ def setup_entry_fixture() -> Generator[AsyncMock]:
4949
yield mock_setup_entry
5050

5151

52+
@pytest.mark.parametrize(
53+
("country", "expected_tx_power"),
54+
[
55+
("US", 8),
56+
("NL", 10),
57+
("JP", 8),
58+
("DE", 10),
59+
],
60+
)
5261
async def test_config_flow_zigbee(
5362
hass: HomeAssistant,
63+
country: str,
64+
expected_tx_power: int,
5465
) -> None:
5566
"""Test Zigbee config flow for Connect ZBT-2."""
67+
hass.config.country = country
68+
5669
fw_type = ApplicationType.EZSP
5770
fw_version = "7.4.4.0 build 0"
5871
model = "Home Assistant Connect ZBT-2"
@@ -146,6 +159,7 @@ async def mock_install_firmware_step(
146159
"flow_control": "hardware",
147160
},
148161
"radio_type": fw_type.value,
162+
"tx_power": expected_tx_power,
149163
}
150164

151165

@@ -382,6 +396,7 @@ async def test_options_flow(
382396
"flow_control": "hardware",
383397
},
384398
"radio_type": "ezsp",
399+
"tx_power": 8,
385400
}
386401

387402

0 commit comments

Comments
 (0)