Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use config dataclasses instead of HA dicts #43

Merged
merged 2 commits into from
Apr 15, 2024
Merged
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
57 changes: 23 additions & 34 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,14 @@
import zigpy.zdo.types as zdo_t

from tests import common
from zha.application.const import (
CONF_ALARM_ARM_REQUIRES_CODE,
CONF_ALARM_FAILED_TRIES,
CONF_ALARM_MASTER_CODE,
CONF_ENABLE_ENHANCED_LIGHT_TRANSITION,
CONF_GROUP_MEMBERS_ASSUME_STATE,
CONF_RADIO_TYPE,
CUSTOM_CONFIGURATION,
ZHA_ALARM_OPTIONS,
ZHA_OPTIONS,
)
from zha.application.gateway import Gateway
from zha.application.helpers import ZHAData
from zha.application.helpers import (
AlarmControlPanelOptions,
CoordinatorConfiguration,
LightOptions,
ZHAConfiguration,
ZHAData,
)
from zha.zigbee.device import Device

FIXTURE_GRP_ID = 0x1001
Expand Down Expand Up @@ -185,29 +180,23 @@ def caplog_fixture(caplog: pytest.LogCaptureFixture) -> pytest.LogCaptureFixture
@pytest.fixture
def zha_data() -> ZHAData:
"""Fixture representing zha configuration data."""

return ZHAData(
yaml_config={},
config_entry_data={
"data": {
zigpy.config.CONF_DEVICE: {
zigpy.config.CONF_DEVICE_PATH: "/dev/ttyUSB0"
},
CONF_RADIO_TYPE: "ezsp",
},
"options": {
CUSTOM_CONFIGURATION: {
ZHA_OPTIONS: {
CONF_ENABLE_ENHANCED_LIGHT_TRANSITION: True,
CONF_GROUP_MEMBERS_ASSUME_STATE: False,
},
ZHA_ALARM_OPTIONS: {
CONF_ALARM_ARM_REQUIRES_CODE: False,
CONF_ALARM_MASTER_CODE: "4321",
CONF_ALARM_FAILED_TRIES: 2,
},
}
},
},
config=ZHAConfiguration(
coordinator_configuration=CoordinatorConfiguration(
radio_type="ezsp",
path="/dev/ttyUSB0",
),
light_options=LightOptions(
enable_enhanced_light_transition=True,
group_members_assume_state=False,
),
alarm_control_panel_options=AlarmControlPanelOptions(
arm_requires_code=False,
master_code="4321",
failed_tries=2,
),
)
)


Expand Down
60 changes: 28 additions & 32 deletions tests/test_discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from zha.application import Platform, discovery
from zha.application.discovery import ENDPOINT_PROBE, PLATFORMS, EndpointProbe
from zha.application.gateway import Gateway
from zha.application.helpers import DeviceOverridesConfiguration
from zha.application.platforms import PlatformEntity
from zha.application.registries import (
PLATFORM_ENTITIES,
Expand Down Expand Up @@ -191,9 +192,7 @@ async def test_devices(
no_tail_id = NO_TAIL_ID.sub("", ent_info[DEV_SIG_ENT_MAP_ID])
message1 = f"No entity found for platform[{platform}] unique_id[{unique_id}] no_tail_id[{no_tail_id}]"

if not contains_ignored_suffix(
unique_id
): # TODO remove this when update is fixed
if not contains_ignored_suffix(unique_id):
assert unique_id in created_entities, message1
entity = created_entities[unique_id]
unhandled_entities.remove(unique_id)
Expand Down Expand Up @@ -275,7 +274,7 @@ def test_discover_by_device_type_override() -> None:
ep_mock.return_value.device_type = 0x0100
type(endpoint).zigpy_endpoint = ep_mock

overrides = {endpoint.unique_id: {"type": Platform.SWITCH}}
overrides = {endpoint.unique_id: DeviceOverridesConfiguration(type=Platform.SWITCH)}
get_entity_mock = mock.MagicMock(
return_value=(mock.sentinel.entity_cls, mock.sentinel.claimed)
)
Expand Down Expand Up @@ -328,8 +327,8 @@ def test_discover_probe_single_cluster() -> None:
@pytest.mark.parametrize("device_info", DEVICES)
async def test_discover_endpoint(
device_info: dict[str, Any],
zha_device_mock: Callable[..., Device],
zha_gateway: Gateway,
zha_device_mock: Callable[..., Device], # pylint: disable=redefined-outer-name
zha_gateway: Gateway, # pylint: disable=unused-argument
) -> None:
"""Test device discovery."""

Expand Down Expand Up @@ -367,20 +366,17 @@ async def test_discover_endpoint(

test_ent_class = ent_info[DEV_SIG_ENT_MAP_CLASS]
test_unique_id_head = UNIQUE_ID_HD.match(unique_id).group(0)
if (
test_ent_class != "FirmwareUpdateEntity"
): # TODO remove this when update is fixed
assert (test_unique_id_head, test_ent_class) in ha_ent_info

entity_platform, entity_unique_id, entity_cluster_handlers = ha_ent_info[
(test_unique_id_head, test_ent_class)
]
assert platform is entity_platform.value
# unique_id used for discover is the same for "multi entities"
assert unique_id.startswith(entity_unique_id)
assert {ch.name for ch in entity_cluster_handlers} == set(
ent_info[DEV_SIG_CLUSTER_HANDLERS]
)
assert (test_unique_id_head, test_ent_class) in ha_ent_info

entity_platform, entity_unique_id, entity_cluster_handlers = ha_ent_info[
(test_unique_id_head, test_ent_class)
]
assert platform is entity_platform.value
# unique_id used for discover is the same for "multi entities"
assert unique_id.startswith(entity_unique_id)
assert {ch.name for ch in entity_cluster_handlers} == set(
ent_info[DEV_SIG_CLUSTER_HANDLERS]
)


def _ch_mock(cluster):
Expand Down Expand Up @@ -410,8 +406,6 @@ def _test_single_input_cluster_device_class(probe_mock):
class QuirkedIAS(zigpy.quirks.CustomCluster, zigpy.zcl.clusters.security.IasZone):
"""Quirked IAS Zone cluster."""

pass

ias_ch = _ch_mock(QuirkedIAS)

class _Analog(zigpy.quirks.CustomCluster, zigpy.zcl.clusters.general.AnalogInput):
Expand Down Expand Up @@ -485,8 +479,10 @@ async def test_device_override(
)

if override is not None:
override = {"device_config": {"00:11:22:33:44:55:66:77-1": {"type": override}}}
zha_gateway.config.yaml_config = override
overrides = {
"00:11:22:33:44:55:66:77-1": DeviceOverridesConfiguration(type=override)
}
zha_gateway.config.config.device_overrides = overrides
discovery.ENDPOINT_PROBE.initialize(zha_gateway)

await zha_gateway.async_device_initialized(zigpy_device)
Expand All @@ -502,7 +498,7 @@ async def test_device_override(


async def test_quirks_v2_entity_discovery(
zha_gateway: Gateway,
zha_gateway: Gateway, # pylint: disable=unused-argument
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should disable unused-argument and redefined-outer-name for any file in tests/?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the fence. the redefined-outer-name one saved me a couple times when converting. I am mainly adding the hints to the files when I know they aren't an issue so I don't get distracted by them in vscode. I'll defer to consensus here.

zigpy_device_mock,
device_joined,
) -> None:
Expand Down Expand Up @@ -566,7 +562,7 @@ async def test_quirks_v2_entity_discovery(


async def test_quirks_v2_entity_discovery_e1_curtain(
zha_gateway: Gateway,
zha_gateway: Gateway, # pylint: disable=unused-argument
zigpy_device_mock,
device_joined,
) -> None:
Expand Down Expand Up @@ -778,7 +774,7 @@ def _get_test_device(


async def test_quirks_v2_entity_no_metadata(
zha_gateway: Gateway,
zha_gateway: Gateway, # pylint: disable=unused-argument
zigpy_device_mock,
device_joined,
caplog: pytest.LogCaptureFixture,
Expand All @@ -797,7 +793,7 @@ async def test_quirks_v2_entity_no_metadata(


async def test_quirks_v2_entity_discovery_errors(
zha_gateway: Gateway,
zha_gateway: Gateway, # pylint: disable=unused-argument
zigpy_device_mock,
device_joined,
caplog: pytest.LogCaptureFixture,
Expand Down Expand Up @@ -846,7 +842,7 @@ def validate_device_class_unit(
quirk: QuirksV2RegistryEntry,
entity_metadata: EntityMetadata,
platform: Platform,
translations: dict,
translations: dict, # pylint: disable=unused-argument
) -> None:
"""Ensure device class and unit are used correctly."""
if (
Expand Down Expand Up @@ -887,7 +883,7 @@ def validate_translation_keys_device_class(
quirk: QuirksV2RegistryEntry,
entity_metadata: EntityMetadata,
platform: Platform,
translations: dict,
translations: dict, # pylint: disable=unused-argument
) -> None:
"""Validate translation keys and device class usage."""
if isinstance(entity_metadata, ZCLCommandButtonMetadata):
Expand Down Expand Up @@ -960,7 +956,7 @@ def validate_metadata(validator: Callable) -> None:
],
)
async def test_quirks_v2_metadata_errors(
zha_gateway: Gateway,
zha_gateway: Gateway, # pylint: disable=unused-argument
zigpy_device_mock,
device_joined,
augment_method: Callable[[QuirksV2RegistryEntry], QuirksV2RegistryEntry],
Expand Down Expand Up @@ -1063,7 +1059,7 @@ def bad_number_device_class(
],
)
async def test_quirks_v2_metadata_bad_device_classes(
zha_gateway: Gateway,
zha_gateway: Gateway, # pylint: disable=unused-argument
zigpy_device_mock,
device_joined,
caplog: pytest.LogCaptureFixture,
Expand Down
8 changes: 4 additions & 4 deletions tests/test_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from tests.common import async_find_group_entity_id, find_entity_id
from tests.conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
from zha.application import Platform
from zha.application.const import RadioType
from zha.application.const import CONF_USE_THREAD, RadioType
from zha.application.gateway import (
DeviceJoinedDeviceInfo,
DeviceJoinedEvent,
Expand Down Expand Up @@ -353,16 +353,16 @@ async def test_gateway_initialize_bellows_thread(
zha_data: ZHAData,
) -> None:
"""Test ZHA disabling the UART thread when connecting to a TCP coordinator."""
zha_data.config_entry_data["data"]["device"]["path"] = device_path
zha_data.yaml_config["zigpy_config"] = config_override
zha_data.config.coordinator_configuration.path = device_path
zha_data.zigpy_config = config_override

with patch(
"bellows.zigbee.application.ControllerApplication.new",
return_value=zigpy_app_controller,
) as mock_new:
zha_gw = Gateway(zha_data)
await zha_gw.async_initialize()
assert mock_new.mock_calls[-1].kwargs["config"]["use_thread"] is thread_state
assert mock_new.mock_calls[-1].kwargs["config"][CONF_USE_THREAD] is thread_state
await zha_gw.shutdown()


Expand Down
16 changes: 4 additions & 12 deletions tests/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@
import zigpy.zcl.foundation as zcl_f

from zha.application import Platform
from zha.application.const import (
CONF_ALWAYS_PREFER_XY_COLOR_MODE,
CONF_GROUP_MEMBERS_ASSUME_STATE,
CUSTOM_CONFIGURATION,
ZHA_OPTIONS,
)
from zha.application.const import CONF_ALWAYS_PREFER_XY_COLOR_MODE
from zha.application.gateway import Gateway
from zha.application.platforms import GroupEntity, PlatformEntity
from zha.application.platforms.light.const import (
Expand Down Expand Up @@ -1015,10 +1010,9 @@ async def test_light_initialization(
# mock attribute reads
zigpy_device.endpoints[1].light_color.PLUGGED_ATTR_READS = plugged_attr_reads

light_options = zha_gateway.config.config.light_options
for key in config_override:
zha_gateway.config.config_entry_data["options"][CUSTOM_CONFIGURATION][
ZHA_OPTIONS
][key] = config_override[key]
setattr(light_options, key, config_override[key])
zha_device = await device_joined(zigpy_device)
entity_id = find_entity_id(Platform.LIGHT, zha_device)
assert entity_id is not None
Expand Down Expand Up @@ -1865,9 +1859,7 @@ async def test_group_member_assume_state(
) -> None:
"""Test the group members assume state function."""

zha_gateway.config.config_entry_data["options"][CUSTOM_CONFIGURATION][ZHA_OPTIONS][
CONF_GROUP_MEMBERS_ASSUME_STATE
] = True
zha_gateway.config.config.light_options.group_members_assume_state = True

zha_gateway.coordinator_zha_device = coordinator
coordinator._zha_gateway = zha_gateway
Expand Down
48 changes: 0 additions & 48 deletions zha/application/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,56 +73,12 @@
CLUSTER_TYPE_IN = "in"
CLUSTER_TYPE_OUT = "out"

CONF_ALARM_MASTER_CODE = "alarm_master_code"
CONF_ALARM_FAILED_TRIES = "alarm_failed_tries"
CONF_ALARM_ARM_REQUIRES_CODE = "alarm_arm_requires_code"

CONF_BAUDRATE = "baudrate"
CONF_FLOW_CONTROL = "flow_control"
CONF_CUSTOM_QUIRKS_PATH = "custom_quirks_path"
CONF_DEFAULT_LIGHT_TRANSITION = "default_light_transition"
CONF_DEVICE_CONFIG = "device_config"
CONF_ENABLE_ENHANCED_LIGHT_TRANSITION = "enhanced_light_transition"
CONF_ENABLE_LIGHT_TRANSITIONING_FLAG = "light_transitioning_flag"
CONF_ALWAYS_PREFER_XY_COLOR_MODE = "always_prefer_xy_color_mode"
CONF_GROUP_MEMBERS_ASSUME_STATE = "group_members_assume_state"
CONF_ENABLE_IDENTIFY_ON_JOIN = "enable_identify_on_join"
CONF_ENABLE_QUIRKS = "enable_quirks"
CONF_RADIO_TYPE = "radio_type"
CONF_USB_PATH = "usb_path"
CONF_USE_THREAD = "use_thread"
CONF_ZIGPY = "zigpy_config"

CONF_CONSIDER_UNAVAILABLE_MAINS = "consider_unavailable_mains"
CONF_DEFAULT_CONSIDER_UNAVAILABLE_MAINS = 60 * 60 * 2 # 2 hours
CONF_CONSIDER_UNAVAILABLE_BATTERY = "consider_unavailable_battery"
CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY = 60 * 60 * 6 # 6 hours

CUSTOM_CONFIGURATION = "custom_configuration"

DATA_DEVICE_CONFIG = "zha_device_config"
DATA_ZHA = "zha"
DATA_ZHA_CONFIG = "config"
DATA_ZHA_CORE_EVENTS = "zha_core_events"
DATA_ZHA_DEVICE_TRIGGER_CACHE = "zha_device_trigger_cache"
DATA_ZHA_GATEWAY = "zha_gateway"

DEFAULT_RADIO_TYPE = "ezsp"
DEFAULT_BAUDRATE = 57600
DEFAULT_DATABASE_NAME = "zigbee.db"

DEVICE_PAIRING_STATUS = "pairing_status"

DISCOVERY_KEY = "zha_discovery_info"

DOMAIN = "zha"

GROUP_ID = "group_id"
GROUP_IDS = "group_ids"
GROUP_NAME = "group_name"

MFG_CLUSTER_ID_START = 0xFC00

POWER_MAINS_POWERED = "Mains"
POWER_BATTERY_OR_UNKNOWN = "Battery or Unknown"

Expand All @@ -140,9 +96,6 @@

ZCL_INIT_ATTRS = "ZCL_INIT_ATTRS"

ZHA_ALARM_OPTIONS = "zha_alarm_options"
ZHA_OPTIONS = "zha_options"

_ControllerClsType = type[zigpy.application.ControllerApplication]


Expand Down Expand Up @@ -227,7 +180,6 @@ def description(self) -> str:
WARNING_DEVICE_SQUAWK_MODE_ARMED = 0
WARNING_DEVICE_SQUAWK_MODE_DISARMED = 1

ZHA_DISCOVERY_NEW = "zha_discovery_new_{}"
ZHA_CLUSTER_HANDLER_MSG = "zha_channel_message"
ZHA_CLUSTER_HANDLER_MSG_BIND = "zha_channel_bind"
ZHA_CLUSTER_HANDLER_MSG_CFG_RPT = "zha_channel_configure_reporting"
Expand Down
Loading
Loading