def test_add_to_registry_legacy_sig(fake_dev): reg = DeviceRegistry() quirk_list = mock.MagicMock() model_dict = mock.MagicMock(spec_set=dict) model_dict.__getitem__.return_value = quirk_list manuf_dict = mock.MagicMock() manuf_dict.__getitem__.return_value = model_dict reg._registry = manuf_dict fake_dev.signature = { 1: {}, 2: {}, 3: { "manufacturer": mock.sentinel.legacy_manufacturer, "model": mock.sentinel.legacy_model, }, } reg.add_to_registry(fake_dev) assert manuf_dict.__getitem__.call_count == 1 assert manuf_dict.__getitem__.call_args[0][ 0] is mock.sentinel.legacy_manufacturer assert model_dict.__getitem__.call_count == 1 assert model_dict.__getitem__.call_args[0][0] is mock.sentinel.legacy_model assert quirk_list.append.call_count == 1 assert quirk_list.append.call_args[0][0] is fake_dev
def test_reg_get_model(fake_dev): assert DeviceRegistry.get_model(fake_dev) is None fake_dev.signature = { 1: {}, 2: {}, 3: { "model": mock.sentinel.legacy_model } } assert DeviceRegistry.get_model(fake_dev) is mock.sentinel.legacy_model fake_dev.signature = { 1: {}, 2: {}, 3: { "model": mock.sentinel.legacy_model }, "endpoints": { 1: {}, 2: {}, 3: { "model": mock.sentinel.ep_model } }, "model": mock.sentinel.model, } assert DeviceRegistry.get_model(fake_dev) is mock.sentinel.model
def test_reg_get_manufacturer(fake_dev): assert DeviceRegistry.get_manufacturer(fake_dev) is None fake_dev.signature = { 1: {}, 2: {}, 3: { "manufacturer": mock.sentinel.legacy_manufacturer }, } assert (DeviceRegistry.get_manufacturer(fake_dev) is mock.sentinel.legacy_manufacturer) fake_dev.signature = { 1: {}, 2: {}, 3: { "manufacturer": mock.sentinel.legacy_manufacturer }, "endpoints": { 1: {}, 2: {}, 3: { "manufacturer": mock.sentinel.ep_manufacturer } }, "manufacturer": mock.sentinel.manufacturer, } assert DeviceRegistry.get_manufacturer( fake_dev) is mock.sentinel.manufacturer
def test_remove_new_sig(fake_dev): fake_dev.signature = { 1: {}, 2: {}, 3: { 'manufacturer': mock.sentinel.legacy_manufacturer, 'model': mock.sentinel.legacy_model, }, 'endpoints': { 1: { 'manufacturer': mock.sentinel.manufacturer, 'model': mock.sentinel.model, } }, 'manufacturer': mock.sentinel.dev_manufacturer, 'model': mock.sentinel.dev_model, } reg = DeviceRegistry() quirk_list = mock.MagicMock() model_dict = mock.MagicMock(spec_set=dict) model_dict.__getitem__.return_value = quirk_list manuf_dict = mock.MagicMock() manuf_dict.__getitem__.return_value = model_dict reg._registry = manuf_dict reg.remove(fake_dev) assert manuf_dict.__getitem__.call_count == 1 assert manuf_dict.__getitem__.call_args[0][0] is mock.sentinel.dev_manufacturer assert model_dict.__getitem__.call_count == 1 assert model_dict.__getitem__.call_args[0][0] is mock.sentinel.dev_model assert quirk_list.append.call_count == 0 assert quirk_list.remove.call_count == 1 assert quirk_list.remove.call_args[0][0] is fake_dev
def test_model_manuf_device_sig(real_device): class TestDevice: signature = {} def __init__(*args, **kwargs): pass def get_signature(self): pass registry = DeviceRegistry() registry.add_to_registry(TestDevice) assert registry.get_device(real_device) is real_device TestDevice.signature["endpoints"] = { 1: { "profile_id": 255, "device_type": 255, "input_clusters": [3], "output_clusters": [6], } } TestDevice.signature["model"] = "x" assert registry.get_device(real_device) is real_device TestDevice.signature["model"] = "model" TestDevice.signature["manufacturer"] = "x" assert registry.get_device(real_device) is real_device TestDevice.signature["manufacturer"] = "manufacturer" assert isinstance(registry.get_device(real_device), TestDevice)
def test_model_manuf_device_sig(real_device): class TestDevice: signature = {} def __init__(*args, **kwargs): pass def get_signature(self): pass registry = DeviceRegistry() registry.add_to_registry(TestDevice) assert registry.get_device(real_device) is real_device TestDevice.signature[SIG_ENDPOINTS] = { 1: { SIG_EP_PROFILE: 255, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } } TestDevice.signature[SIG_MODEL] = "x" assert registry.get_device(real_device) is real_device TestDevice.signature[SIG_MODEL] = "model" TestDevice.signature[SIG_MANUFACTURER] = "x" assert registry.get_device(real_device) is real_device TestDevice.signature[SIG_MANUFACTURER] = "manufacturer" assert isinstance(registry.get_device(real_device), TestDevice)
def test_model_manuf_device_sig(real_device): class TestDevice: signature = {} def __init__(*args, **kwargs): pass def get_signature(self): pass registry = DeviceRegistry() registry.add_to_registry(TestDevice) assert registry.get_device(real_device) is real_device TestDevice.signature['endpoints'] = { 1: { 'profile_id': 255, 'device_type': 255, 'input_clusters': [3], 'output_clusters': [6], } } TestDevice.signature['model'] = 'x' assert registry.get_device(real_device) is real_device TestDevice.signature['model'] = 'model' TestDevice.signature['manufacturer'] = 'x' assert registry.get_device(real_device) is real_device TestDevice.signature['manufacturer'] = 'manufacturer' assert isinstance(registry.get_device(real_device), TestDevice)
def test_quirk_match_order(real_device, real_device_2): """Test quirk matching order to allow user overrides via custom quirks.""" class BuiltInQuirk(zigpy.quirks.CustomDevice): signature = { SIG_MODELS_INFO: (("manufacturer", "model"),), SIG_ENDPOINTS: { 1: { SIG_EP_PROFILE: 255, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } }, } def get_signature(self): pass class CustomQuirk(BuiltInQuirk): pass registry = DeviceRegistry() registry.add_to_registry(BuiltInQuirk) # With only a single matching quirk there is no choice but to use the first one assert type(registry.get_device(real_device)) is BuiltInQuirk registry.add_to_registry(CustomQuirk) # A quirk registered later that also matches the device will be preferred assert type(registry.get_device(real_device)) is CustomQuirk
def test_add_to_registry_models_info(fake_dev): fake_dev.signature = { 1: {}, 2: {}, 3: { "manufacturer": mock.sentinel.legacy_manufacturer, "model": mock.sentinel.legacy_model, }, "endpoints": { 1: { "manufacturer": mock.sentinel.manufacturer, "model": mock.sentinel.model, } }, SIG_MODELS_INFO: [ (mock.sentinel.manuf_1, mock.sentinel.model_1), (mock.sentinel.manuf_2, mock.sentinel.model_2), ], } reg = DeviceRegistry() quirk_list = mock.MagicMock() model_dict = mock.MagicMock(spec_set=dict) model_dict.__getitem__.return_value = quirk_list manuf_dict = mock.MagicMock() manuf_dict.__getitem__.return_value = model_dict reg._registry = manuf_dict reg.add_to_registry(fake_dev) assert manuf_dict.__getitem__.call_count == 2 assert manuf_dict.__getitem__.call_args_list[0][0][ 0] is mock.sentinel.manuf_1 assert manuf_dict.__getitem__.call_args_list[1][0][ 0] is mock.sentinel.manuf_2 assert model_dict.__getitem__.call_count == 2 assert model_dict.__getitem__.call_args_list[0][0][ 0] is mock.sentinel.model_1 assert model_dict.__getitem__.call_args_list[1][0][ 0] is mock.sentinel.model_2 assert quirk_list.append.call_count == 2 assert quirk_list.append.call_args_list[0][0][0] is fake_dev assert quirk_list.append.call_args_list[1][0][0] is fake_dev quirk_list.reset_mock() model_dict.reset_mock() manuf_dict.reset_mock()
def test_reg_get_manufacturer(fake_dev): assert DeviceRegistry.get_manufacturer(fake_dev) is None fake_dev.signature = { 1: {}, 2: {}, 3: {'manufacturer': mock.sentinel.legacy_manufacturer}, } assert DeviceRegistry.get_manufacturer(fake_dev) is mock.sentinel.legacy_manufacturer fake_dev.signature = { 1: {}, 2: {}, 3: {'manufacturer': mock.sentinel.legacy_manufacturer}, 'endpoints': { 1: {}, 2: {}, 3: {'manufacturer': mock.sentinel.ep_manufacturer} }, 'manufacturer': mock.sentinel.manufacturer } assert DeviceRegistry.get_manufacturer(fake_dev) is mock.sentinel.manufacturer
import logging from typing import Any, Dict, Optional import zigpy.device import zigpy.endpoint from zigpy.quirks.registry import DeviceRegistry import zigpy.zcl import zigpy.zcl.foundation as foundation _LOGGER = logging.getLogger(__name__) _DEVICE_REGISTRY = DeviceRegistry() def get_device(device, registry=_DEVICE_REGISTRY): """Get a CustomDevice object, if one is available""" return registry.get_device(device) class Registry(type): def __init__(cls, name, bases, nmspc): # noqa: N805 super(Registry, cls).__init__(name, bases, nmspc) if hasattr(cls, "signature"): _DEVICE_REGISTRY.add_to_registry(cls) class CustomDevice(zigpy.device.Device, metaclass=Registry): replacement = {} def __init__(self, application, ieee, nwk, replaces): super().__init__(application, ieee, nwk)
def _dev_reg(device): registry = DeviceRegistry() registry.add_to_registry(device) return registry
def test_get_device_old_signature(real_device): class TestDevice: signature = {} def __init__(*args, **kwargs): pass def get_signature(self): pass registry = DeviceRegistry() registry.add_to_registry(TestDevice) assert registry.get_device(real_device) is real_device TestDevice.signature[1] = {'profile_id': 1} assert registry.get_device(real_device) is real_device TestDevice.signature[1]['profile_id'] = 255 TestDevice.signature[1]['device_type'] = 1 assert registry.get_device(real_device) is real_device TestDevice.signature[1]['device_type'] = 255 TestDevice.signature[1]['input_clusters'] = [1] assert registry.get_device(real_device) is real_device TestDevice.signature[1]['input_clusters'] = [3] TestDevice.signature[1]['output_clusters'] = [1] assert registry.get_device(real_device) is real_device TestDevice.signature[1]['output_clusters'] = [6] TestDevice.signature[1]['model'] = 'x' assert registry.get_device(real_device) is real_device TestDevice.signature[1]['model'] = 'model' TestDevice.signature[1]['manufacturer'] = 'x' assert registry.get_device(real_device) is real_device TestDevice.signature[1]['manufacturer'] = 'manufacturer' assert isinstance(registry.get_device(real_device), TestDevice)
def test_get_device_old_signature(real_device): class TestDevice: signature = {} def __init__(*args, **kwargs): pass def get_signature(self): pass registry = DeviceRegistry() registry.add_to_registry(TestDevice) assert registry.get_device(real_device) is real_device TestDevice.signature[1] = {"profile_id": 1} assert registry.get_device(real_device) is real_device TestDevice.signature[1]["profile_id"] = 255 TestDevice.signature[1]["device_type"] = 1 assert registry.get_device(real_device) is real_device TestDevice.signature[1]["device_type"] = 255 TestDevice.signature[1]["input_clusters"] = [1] assert registry.get_device(real_device) is real_device TestDevice.signature[1]["input_clusters"] = [3] TestDevice.signature[1]["output_clusters"] = [1] assert registry.get_device(real_device) is real_device TestDevice.signature[1]["output_clusters"] = [6] TestDevice.signature[1]["model"] = "x" assert registry.get_device(real_device) is real_device TestDevice.signature[1]["model"] = "model" TestDevice.signature[1]["manufacturer"] = "x" assert registry.get_device(real_device) is real_device TestDevice.signature[1]["manufacturer"] = "manufacturer" assert isinstance(registry.get_device(real_device), TestDevice)
def test_quirk_wildcard_manufacturer(real_device, real_device_2): """Test quirk matching with a wildcard (None) manufacturer.""" class BaseDev(zigpy.quirks.CustomDevice): def get_signature(self): pass class ModelsQuirk(BaseDev): signature = { SIG_MODELS_INFO: (("manufacturer", "model"),), SIG_ENDPOINTS: { 1: { SIG_EP_PROFILE: 255, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } }, } class ModelsQuirkNoMatch(BaseDev): # same model and manufacture, different endpoint signature signature = { SIG_MODELS_INFO: (("manufacturer", "model"),), SIG_ENDPOINTS: { 1: { SIG_EP_PROFILE: 260, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } }, } class ModelOnlyQuirk(BaseDev): # Wildcard Manufacturer signature = { SIG_MODEL: "model", SIG_ENDPOINTS: { 1: { SIG_EP_PROFILE: 255, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } }, } class ModelOnlyQuirkNoMatch(BaseDev): # Wildcard Manufacturer, none matching endpoint signature signature = { SIG_MODEL: "model", SIG_ENDPOINTS: { 1: { SIG_EP_PROFILE: 260, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } }, } registry = DeviceRegistry() for quirk in ModelsQuirk, ModelsQuirkNoMatch, ModelOnlyQuirk, ModelOnlyQuirkNoMatch: registry.add_to_registry(quirk) quirked = registry.get_device(real_device) assert isinstance(quirked, ModelsQuirk) quirked = registry.get_device(real_device_2) assert isinstance(quirked, ModelOnlyQuirk) real_device.manufacturer = ( "We are expected to match a manufacturer wildcard quirk now" ) quirked = registry.get_device(real_device) assert isinstance(quirked, ModelOnlyQuirk) real_device.model = "And now we should not match any quirk" quirked = registry.get_device(real_device) assert quirked is real_device
def test_different_manuf_same_model(real_device, real_device_2): """Test quirk matching for same model, but different manufacturers.""" class TestDevice_1(zigpy.quirks.CustomDevice): signature = { SIG_MODELS_INFO: (("manufacturer", "model"),), SIG_ENDPOINTS: { 1: { SIG_EP_PROFILE: 255, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } }, } def get_signature(self): pass class TestDevice_2(zigpy.quirks.CustomDevice): signature = { SIG_MODELS_INFO: (("A different manufacturer", "model"),), SIG_ENDPOINTS: { 1: { SIG_EP_PROFILE: 255, SIG_EP_TYPE: 255, SIG_EP_INPUT: [3], SIG_EP_OUTPUT: [6], } }, } def get_signature(self): pass registry = DeviceRegistry() registry.add_to_registry(TestDevice_1) assert isinstance(registry.get_device(real_device), TestDevice_1) assert registry.get_device(real_device_2) is real_device_2 registry.add_to_registry(TestDevice_2) assert isinstance(registry.get_device(real_device_2), TestDevice_2) assert not zigpy.quirks.get_quirk_list("manufacturer", "no such model") assert not zigpy.quirks.get_quirk_list("manufacturer", "no such model", registry) assert not zigpy.quirks.get_quirk_list("A different manufacturer", "no such model") assert not zigpy.quirks.get_quirk_list( "A different manufacturer", "no such model", registry ) assert not zigpy.quirks.get_quirk_list("no such manufacturer", "model") assert not zigpy.quirks.get_quirk_list("no such manufacturer", "model", registry) manuf1_list = zigpy.quirks.get_quirk_list("manufacturer", "model", registry) assert len(manuf1_list) == 1 assert manuf1_list[0] is TestDevice_1 manuf2_list = zigpy.quirks.get_quirk_list( "A different manufacturer", "model", registry ) assert len(manuf2_list) == 1 assert manuf2_list[0] is TestDevice_2