Example #1
0
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()
Example #2
0
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)})
Example #3
0
    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"
Example #4
0
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"