Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 100 additions & 1 deletion tests/test_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@

import pytest
from zigpy.application import ControllerApplication
from zigpy.config import CONF_NWK, CONF_NWK_COUNTRY_CODE
from zigpy.config import (
CONF_NWK,
CONF_NWK_COUNTRY_CODE,
CONF_OTA,
CONF_OTA_EXTRA_PROVIDERS,
CONF_OTA_PROVIDER_CHANNEL,
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS,
CONF_OTA_PROVIDER_TYPE,
)
from zigpy.profiles import zha
import zigpy.types
from zigpy.zcl.clusters import general, lighting
Expand Down Expand Up @@ -837,6 +845,97 @@ async def test_country_code_passthrough(
)


@pytest.mark.parametrize(
("use_beta_channel", "yaml_config", "expected_extra_providers"),
[
# Beta channel disabled (default) - no extra providers added
(False, {}, None),
# Beta channel enabled - zigpy_ota provider with beta channel added
(
True,
{},
[
{
CONF_OTA_PROVIDER_TYPE: "zigpy_ota",
CONF_OTA_PROVIDER_CHANNEL: "beta",
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS: True,
}
],
),
# Beta channel enabled with existing OTA config - provider appended
(
True,
{CONF_OTA: {}},
[
{
CONF_OTA_PROVIDER_TYPE: "zigpy_ota",
CONF_OTA_PROVIDER_CHANNEL: "beta",
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS: True,
}
],
),
# Beta channel enabled with existing non-zigpy_ota extra_providers - provider appended
(
True,
{CONF_OTA: {CONF_OTA_EXTRA_PROVIDERS: [{CONF_OTA_PROVIDER_TYPE: "ikea"}]}},
[
{CONF_OTA_PROVIDER_TYPE: "ikea"},
{
CONF_OTA_PROVIDER_TYPE: "zigpy_ota",
CONF_OTA_PROVIDER_CHANNEL: "beta",
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS: True,
},
],
),
# Beta channel enabled but zigpy_ota already in YAML - YAML takes precedence
(
True,
{
CONF_OTA: {
CONF_OTA_EXTRA_PROVIDERS: [
{
CONF_OTA_PROVIDER_TYPE: "zigpy_ota",
CONF_OTA_PROVIDER_CHANNEL: "dev",
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS: True,
}
]
}
},
[
{
CONF_OTA_PROVIDER_TYPE: "zigpy_ota",
CONF_OTA_PROVIDER_CHANNEL: "dev",
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS: True,
}
],
),
],
)
async def test_ota_beta_channel_passthrough(
zha_data: ZHAData,
use_beta_channel: bool,
yaml_config: dict,
expected_extra_providers: list | None,
) -> None:
"""Test OTA beta channel config passthrough to zigpy."""
zha_data.config.ota_configuration.use_beta_channel = use_beta_channel
zha_data.zigpy_config = yaml_config

gateway = Gateway(zha_data)
_, app_config = gateway.get_application_controller_data()

if expected_extra_providers is None:
assert (
CONF_OTA not in app_config
or CONF_OTA_EXTRA_PROVIDERS not in app_config.get(CONF_OTA, {})
)
else:
assert (
app_config.get(CONF_OTA, {}).get(CONF_OTA_EXTRA_PROVIDERS)
== expected_extra_providers
)


async def test_gateway_network_scan(zha_gateway: Gateway) -> None:
"""Test gateway network_scan method."""
channels = zigpy.types.Channels.from_channel_list([11, 15, 20, 25])
Expand Down
23 changes: 23 additions & 0 deletions zha/application/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
CONF_NWK,
CONF_NWK_COUNTRY_CODE,
CONF_NWK_VALIDATE_SETTINGS,
CONF_OTA,
CONF_OTA_EXTRA_PROVIDERS,
CONF_OTA_PROVIDER_CHANNEL,
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS,
CONF_OTA_PROVIDER_TYPE,
)
import zigpy.device
import zigpy.endpoint
Expand Down Expand Up @@ -225,6 +230,24 @@ def get_application_controller_data(self) -> tuple[ControllerApplication, dict]:
):
app_config[CONF_USE_THREAD] = False

# Configure zigpy-ota beta channel if enabled, preferring explicit YAML config
if self.config.config.ota_configuration.use_beta_channel:
extra_providers = app_config.get(CONF_OTA, {}).get(
CONF_OTA_EXTRA_PROVIDERS, []
)
has_zigpy_ota = any(
p.get(CONF_OTA_PROVIDER_TYPE) == "zigpy_ota" for p in extra_providers
)
if not has_zigpy_ota:
app_config.setdefault(CONF_OTA, {})
app_config[CONF_OTA].setdefault(CONF_OTA_EXTRA_PROVIDERS, []).append(
{
CONF_OTA_PROVIDER_TYPE: "zigpy_ota",
CONF_OTA_PROVIDER_CHANNEL: "beta",
CONF_OTA_PROVIDER_OVERRIDE_PREVIOUS: True,
}
)

return self.radio_type.controller, app_config

@classmethod
Expand Down
10 changes: 10 additions & 0 deletions zha/application/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ class QuirksConfiguration:
custom_quirks_path: str | None = dataclasses.field(default=None)


@dataclass(kw_only=True, slots=True)
class OTAConfiguration:
"""ZHA OTA firmware configuration."""

use_beta_channel: bool = dataclasses.field(default=False)


@dataclass(kw_only=True, slots=True)
class DeviceOverridesConfiguration:
"""ZHA device overrides configuration."""
Expand All @@ -364,6 +371,9 @@ class ZHAConfiguration:
quirks_configuration: QuirksConfiguration = dataclasses.field(
default_factory=QuirksConfiguration
)
ota_configuration: OTAConfiguration = dataclasses.field(
default_factory=OTAConfiguration
)
device_overrides: dict[str, DeviceOverridesConfiguration] = dataclasses.field(
default_factory=dict
)
Expand Down
Loading