Skip to content

Commit

Permalink
Use config dataclasses instead of HA dicts (#43)
Browse files Browse the repository at this point in the history
* Use config dataclasses instead of HA dicts

* remove unused method
  • Loading branch information
dmulcahey authored Apr 15, 2024
1 parent c7bf27d commit 4143035
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 250 deletions.
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
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

0 comments on commit 4143035

Please sign in to comment.