"""Test configuration for the ZHA component.""" from unittest import mock import pytest import zigpy from zigpy.application import ControllerApplication import zigpy.config import zigpy.group import zigpy.types import homeassistant.components.zha.core.const as zha_const import homeassistant.components.zha.core.device as zha_core_device import homeassistant.components.zha.core.registries as zha_regs from homeassistant.setup import async_setup_component from .common import FakeDevice, FakeEndpoint, get_zha_gateway import tests.async_mock from tests.common import MockConfigEntry FIXTURE_GRP_ID = 0x1001 FIXTURE_GRP_NAME = "fixture group" @pytest.fixture def zigpy_app_controller(): """Zigpy ApplicationController fixture.""" app = mock.MagicMock(spec_set=ControllerApplication) app.startup = tests.async_mock.AsyncMock() app.shutdown = tests.async_mock.AsyncMock() groups = zigpy.group.Groups(app) groups.add_group(FIXTURE_GRP_ID, FIXTURE_GRP_NAME, suppress_event=True) app.configure_mock(groups=groups) type(app).ieee = mock.PropertyMock() app.ieee.return_value = zigpy.types.EUI64.convert("00:15:8d:00:02:32:4f:32") type(app).nwk = mock.PropertyMock(return_value=zigpy.types.NWK(0x0000)) type(app).devices = mock.PropertyMock(return_value={}) return app @pytest.fixture def zigpy_radio(): """Zigpy radio mock.""" radio = mock.MagicMock() radio.connect = tests.async_mock.AsyncMock() return radio @pytest.fixture(name="config_entry") async def config_entry_fixture(hass): """Fixture representing a config entry.""" entry = MockConfigEntry( version=2, domain=zha_const.DOMAIN, data={ zigpy.config.CONF_DEVICE: {zigpy.config.CONF_DEVICE_PATH: "/dev/ttyUSB0"}, zha_const.CONF_RADIO_TYPE: "MockRadio", }, ) entry.add_to_hass(hass) return entry @pytest.fixture def setup_zha(hass, config_entry, zigpy_app_controller, zigpy_radio): """Set up ZHA component.""" zha_config = {zha_const.CONF_ENABLE_QUIRKS: False} app_ctrl = mock.MagicMock() app_ctrl.new = tests.async_mock.AsyncMock(return_value=zigpy_app_controller) app_ctrl.SCHEMA = zigpy.config.CONFIG_SCHEMA app_ctrl.SCHEMA_DEVICE = zigpy.config.SCHEMA_DEVICE radio_details = { zha_const.CONTROLLER: app_ctrl, zha_const.ZHA_GW_RADIO_DESCRIPTION: "mock radio", } async def _setup(config=None): config = config or {} with mock.patch.dict(zha_regs.RADIO_TYPES, {"MockRadio": radio_details}): status = await async_setup_component( hass, zha_const.DOMAIN, {zha_const.DOMAIN: {**zha_config, **config}} ) assert status is True await hass.async_block_till_done() return _setup @pytest.fixture def channel(): """Channel mock factory fixture.""" def channel(name: str, cluster_id: int, endpoint_id: int = 1): ch = mock.MagicMock() ch.name = name ch.generic_id = f"channel_0x{cluster_id:04x}" ch.id = f"{endpoint_id}:0x{cluster_id:04x}" ch.async_configure = tests.async_mock.AsyncMock() ch.async_initialize = tests.async_mock.AsyncMock() return ch return channel @pytest.fixture def zigpy_device_mock(zigpy_app_controller): """Make a fake device using the specified cluster classes.""" def _mock_dev( endpoints, ieee="00:0d:6f:00:0a:90:69:e7", manufacturer="FakeManufacturer", model="FakeModel", node_descriptor=b"\x02@\x807\x10\x7fd\x00\x00*d\x00\x00", nwk=0xB79C, ): """Make a fake device using the specified cluster classes.""" device = FakeDevice( zigpy_app_controller, ieee, manufacturer, model, node_descriptor, nwk=nwk ) for epid, ep in endpoints.items(): endpoint = FakeEndpoint(manufacturer, model, epid) endpoint.device = device device.endpoints[epid] = endpoint endpoint.device_type = ep["device_type"] profile_id = ep.get("profile_id") if profile_id: endpoint.profile_id = profile_id for cluster_id in ep.get("in_clusters", []): endpoint.add_input_cluster(cluster_id) for cluster_id in ep.get("out_clusters", []): endpoint.add_output_cluster(cluster_id) return device return _mock_dev @pytest.fixture def zha_device_joined(hass, setup_zha): """Return a newly joined ZHA device.""" async def _zha_device(zigpy_dev): await setup_zha() zha_gateway = get_zha_gateway(hass) await zha_gateway.async_device_initialized(zigpy_dev) await hass.async_block_till_done() return zha_gateway.get_device(zigpy_dev.ieee) return _zha_device @pytest.fixture def zha_device_restored(hass, zigpy_app_controller, setup_zha): """Return a restored ZHA device.""" async def _zha_device(zigpy_dev): zigpy_app_controller.devices[zigpy_dev.ieee] = zigpy_dev await setup_zha() zha_gateway = hass.data[zha_const.DATA_ZHA][zha_const.DATA_ZHA_GATEWAY] return zha_gateway.get_device(zigpy_dev.ieee) return _zha_device @pytest.fixture(params=["zha_device_joined", "zha_device_restored"]) def zha_device_joined_restored(request): """Join or restore ZHA device.""" named_method = request.getfixturevalue(request.param) named_method.name = request.param return named_method @pytest.fixture def zha_device_mock(hass, zigpy_device_mock): """Return a zha Device factory.""" def _zha_device( endpoints=None, ieee="00:11:22:33:44:55:66:77", manufacturer="mock manufacturer", model="mock model", node_desc=b"\x02@\x807\x10\x7fd\x00\x00*d\x00\x00", ): if endpoints is None: endpoints = { 1: { "in_clusters": [0, 1, 8, 768], "out_clusters": [0x19], "device_type": 0x0105, }, 2: { "in_clusters": [0], "out_clusters": [6, 8, 0x19, 768], "device_type": 0x0810, }, } zigpy_device = zigpy_device_mock( endpoints, ieee, manufacturer, model, node_desc ) zha_device = zha_core_device.ZHADevice(hass, zigpy_device, mock.MagicMock()) return zha_device return _zha_device