def globally_load_quirks(): """Load quirks automatically so that ZHA tests run deterministically in isolation. If portions of the ZHA test suite that do not happen to load quirks are run independently, bugs can emerge that will show up only when more of the test suite is run. """ import zhaquirks zhaquirks.setup()
def test_quirk_loading_error(tmp_path): """Ensure quirks do not silently fail to load.""" custom_quirks = tmp_path / "custom_zha_quirks" custom_quirks.mkdir() (custom_quirks / "__init__.py").touch() (custom_quirks / "bosch").mkdir() (custom_quirks / "bosch/__init__.py").touch() # (custom_quirks / "bosch/custom_quirk.py").write_text('1/0') # Syntax errors are not swallowed (custom_quirks / "bosch/custom_quirk.py").write_text("1/") with pytest.raises(SyntaxError): zhaquirks.setup({zhaquirks.CUSTOM_QUIRKS_PATH: str(custom_quirks)}) # Nor are import errors (custom_quirks / "bosch/custom_quirk.py").write_text("from os import foobarbaz7") with pytest.raises(ImportError): zhaquirks.setup({zhaquirks.CUSTOM_QUIRKS_PATH: str(custom_quirks)})
ON, OUTPUT_CLUSTERS, PROFILE_ID, ZONE_STATE, ) from zhaquirks.tuya import Data, TuyaManufClusterAttributes import zhaquirks.tuya.electric_heating import zhaquirks.tuya.motion import zhaquirks.tuya.siren import zhaquirks.tuya.ts0042 import zhaquirks.tuya.ts0043 import zhaquirks.tuya.valve from tests.common import ClusterListener zhaquirks.setup() ZCL_TUYA_SET_TIME_REQUEST = b"\tp\x24\x00\00" ZCL_TUYA_MOTION = b"\tL\x01\x00\x05\x03\x04\x00\x01\x02" ZCL_TUYA_SWITCH_ON = b"\tQ\x02\x006\x01\x01\x00\x01\x01" ZCL_TUYA_SWITCH_OFF = b"\tQ\x02\x006\x01\x01\x00\x01\x00" ZCL_TUYA_ATTRIBUTE_617_TO_179 = b"\tp\x02\x00\x02i\x02\x00\x04\x00\x00\x00\xb3" ZCL_TUYA_SIREN_TEMPERATURE = ZCL_TUYA_ATTRIBUTE_617_TO_179 ZCL_TUYA_SIREN_HUMIDITY = b"\tp\x02\x00\x02j\x02\x00\x04\x00\x00\x00U" ZCL_TUYA_SIREN_ON = b"\t\t\x02\x00\x04h\x01\x00\x01\x01" ZCL_TUYA_SIREN_OFF = b"\t\t\x02\x00\x04h\x01\x00\x01\x00" ZCL_TUYA_VALVE_TEMPERATURE = b"\tp\x02\x00\x02\x03\x02\x00\x04\x00\x00\x00\xb3" ZCL_TUYA_VALVE_TARGET_TEMP = b"\t3\x01\x03\x05\x02\x02\x00\x04\x00\x00\x002" ZCL_TUYA_VALVE_OFF = b"\t2\x01\x03\x04\x04\x04\x00\x01\x00" ZCL_TUYA_VALVE_SCHEDULE = b"\t2\x01\x03\x04\x04\x04\x00\x01\x01"
def test_custom_quirk_loading(zigpy_device_from_quirk, tmp_path): """Make sure custom quirks take priority over regular quirks.""" device = zigpy_device_from_quirk( zhaquirks.bosch.motion.ISWZPR1WP13, apply_quirk=False ) assert type(device) is zigpy.device.Device # Make sure our target quirk will load after we re-setup zhaquirks zhaquirks.setup() assert type(zq.get_device(device)) is zhaquirks.bosch.motion.ISWZPR1WP13 custom_quirks = tmp_path / "custom_zha_quirks" custom_quirks.mkdir() # Make our own custom quirk (custom_quirks / "__init__.py").touch() (custom_quirks / "bosch").mkdir() (custom_quirks / "bosch/__init__.py").touch() (custom_quirks / "bosch/custom_quirk.py").write_text( ''' """Device handler for Bosch motion sensors.""" from zigpy.profiles import zha from zigpy.quirks import CustomDevice from zigpy.zcl.clusters.general import Basic, Identify, Ota, PollControl from zigpy.zcl.clusters.homeautomation import Diagnostic from zigpy.zcl.clusters.measurement import TemperatureMeasurement from zigpy.zcl.clusters.security import IasZone from zhaquirks import PowerConfigurationCluster from zhaquirks.bosch import BOSCH from zhaquirks.const import ( DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, ) class TestReplacementISWZPR1WP13(CustomDevice): """Custom device representing Bosch motion sensors.""" signature = { # <SimpleDescriptor endpoint=1 profile=260 device_type=1026 # device_version=0 # input_clusters=[0, 1, 3, 1026, 1280, 32, 2821] # output_clusters=[25]> MODELS_INFO: [(BOSCH, "ISW-ZPR1-WP13")], ENDPOINTS: { 5: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.IAS_ZONE, INPUT_CLUSTERS: [ Basic.cluster_id, PowerConfigurationCluster.cluster_id, Identify.cluster_id, PollControl.cluster_id, TemperatureMeasurement.cluster_id, IasZone.cluster_id, Diagnostic.cluster_id, ], OUTPUT_CLUSTERS: [Ota.cluster_id], } }, } replacement = { ENDPOINTS: { 5: { INPUT_CLUSTERS: [ Basic.cluster_id, PowerConfigurationCluster.cluster_id, Identify.cluster_id, PollControl.cluster_id, TemperatureMeasurement.cluster_id, IasZone.cluster_id, Diagnostic.cluster_id, ], OUTPUT_CLUSTERS: [Ota.cluster_id], } } } ''' ) zhaquirks.setup({zhaquirks.CUSTOM_QUIRKS_PATH: str(custom_quirks)}) assert not isinstance(zq.get_device(device), zhaquirks.bosch.motion.ISWZPR1WP13) assert type(zq.get_device(device)).__name__ == "TestReplacementISWZPR1WP13"