### Bash Script for Development Environment Setup Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md Run this bash script from the project root to install all necessary dependencies and the pre-commit hook. It ensures your development environment is set up correctly. ```bash script/setup ``` -------------------------------- ### Barebones Tuya v2 Quirk Setup Source: https://github.com/zigpy/zha-device-handlers/wiki/Tuya-‐-v2-Quirk-with-TuyaQuirkBuilder Initializes a basic Tuya v2 quirk using TuyaQuirkBuilder. This serves as a starting point for adding device-specific configurations. ```python from zigpy.quirks.v2 import EntityType import zigpy.types as t from zhaquirks.tuya.builder import TuyaQuirkBuilder ( TuyaQuirkBuilder("_TZE200_laqjm8qd", "TS0601") .skip_configuration() .add_to_registry() ) ``` -------------------------------- ### v2 TuyaQuirkBuilder Example Source: https://github.com/zigpy/zha-device-handlers/wiki/Tuya-‐-v2-Quirk-with-TuyaQuirkBuilder Example of building a v2 quirk for a Tuya device using TuyaQuirkBuilder, defining multiple switches with specific data points and attributes. ```python from zigpy.quirks.v2 import EntityType import zigpy.types as t from zhaquirks.tuya.builder import TuyaQuirkBuilder ( TuyaQuirkBuilder("_TZE200_laqjm8qd", "TS0601") .tuya_switch( dp_id=1, attribute_name="on_off_1", entity_type=EntityType.STANDARD, translation_key="on_off_1", fallback_name="Switch 1", ) .tuya_switch( dp_id=2, attribute_name="on_off_2", entity_type=EntityType.STANDARD, translation_key="on_off_2", fallback_name="Switch 2", ) .tuya_switch( dp_id=3, attribute_name="on_off_3", entity_type=EntityType.STANDARD, translation_key="on_off_3", fallback_name="Switch 3", ) .tuya_switch( dp_id=4, attribute_name="on_off_4", entity_type=EntityType.STANDARD, translation_key="on_off_4", fallback_name="Switch 4", ) .tuya_switch( dp_id=5, attribute_name="on_off_5", entity_type=EntityType.STANDARD, translation_key="on_off_5", fallback_name="Switch 5", ) .skip_configuration() .add_to_registry() ) ``` -------------------------------- ### Quirk Signature Example Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md A Python example demonstrating how to define a quirk signature for a specific device, including model information and endpoint details. ```python signature = { MODELS_INFO: [(LUMI, "lumi.plug.maus01")], ENDPOINTS: { # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, PowerConfiguration.cluster_id, DeviceTemperature.cluster_id, Groups.cluster_id, Identify.cluster_id, OnOff.cluster_id, Scenes.cluster_id, BinaryOutput.cluster_id, Time.cluster_id, ElectricalMeasurement.cluster_id, ], OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id], }, }, } ``` -------------------------------- ### Node Descriptor Example Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md An example of a Node Descriptor, which provides basic device attributes like manufacturer code and power type. ```text ``` -------------------------------- ### Simple Descriptor Example Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md An example of a Simple Descriptor, detailing a Zigbee device endpoint's functionality including profile ID, device type, and cluster lists. ```text ``` -------------------------------- ### Expose a Switch Entity for Device Control Source: https://github.com/zigpy/zha-device-handlers/blob/dev/CLAUDE.md Creates a switch entity in Home Assistant to control a device attribute. This example exposes the 'led_enable' attribute, allowing it to be toggled on or off. ```python .switch( attribute_name="led_enable", cluster_id=CustomCluster.cluster_id, cluster_type=ClusterType.Server, # Optional: default Server; use ClusterType.Client for out_clusters force_inverted=False, # Optional: invert on/off off_value=0, # Optional: value written when turning off (default 0) on_value=1, # Optional: value written when turning on (default 1) translation_key="led_enable", fallback_name="LED enable", ) ``` -------------------------------- ### Example Tuya Quirk with TuyaQuirkBuilder Source: https://github.com/zigpy/zha-device-handlers/blob/dev/tuya.md An example of a Tuya quirk using TuyaQuirkBuilder to define temperature, humidity, and battery datapoints. It also skips configuration steps. ```python from zhaquirks.tuya.builder import TuyaQuirkBuilder ( TuyaQuirkBuilder("_TZE200_bjawzodf", "TS0601") .applies_to("_TZE200_zl1kmjqx", "TS0601") .tuya_temperature(dp_id=1, scale=10) .tuya_humidity(dp_id=2, scale=10) .tuya_battery(dp_id=4) .skip_configuration() .add_to_registry() ) ``` -------------------------------- ### Python Example for Complex ZHA Event Matching Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md This Python dictionary demonstrates matching a more complex zha_event, like the 'dim up' action on a Hue remote. It includes additional parameters like CLUSTER_ID, ENDPOINT_ID, and PARAMS to uniquely identify the event when a simple command is insufficient. ```python {COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, PARAMS: {'step_mode': 0}} ``` -------------------------------- ### Example Tuya Datapoints Source: https://github.com/zigpy/zha-device-handlers/wiki/Tuya-‐-v2-Quirk-with-TuyaQuirkBuilder A list of example Tuya Datapoints (DPs) and their descriptions, often found from the Tuya developer console or diagnostic output. ```text "1":"Switch" "2":"Start" "101":"Last irrigation time." "102":"Next irrigation time." "103":"Real-time irrigation method (frequency)" "104":"Duration" "105":"Real-time Irrigation Interval (Seconds)" "106":"Current temperature (Celsius)" "107":"Smart Weather" "108":"Current battery level (%)" "109":"Circular irrigation parameters." "110":"Real-time cumulative duration (seconds)" "111":"Real-time accumulated water volume (liters)" "112":"Other extensions." "113":"Timing function." "114":"统计功能" "115":"时区" ``` -------------------------------- ### Configure Attribute Reporting for a Sensor Source: https://github.com/zigpy/zha-device-handlers/blob/dev/CLAUDE.md Sets up automatic attribute reporting for a sensor. This example configures reporting for a 'measured_value' attribute on the VOCIndex cluster with specified intervals and reportable change. ```python .sensor( attribute_name="measured_value", cluster_id=VOCIndex.cluster_id, reporting_config=ReportingConfig( min_interval=60, # Minimum seconds between reports max_interval=120, # Maximum seconds between reports reportable_change=1, # Minimum change to trigger report ), ... ) ``` -------------------------------- ### YAML Example for SimpleDescriptor Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md This YAML format is used to include SimpleDescriptor entries for each endpoint in the signature dictionary when defining custom devices. Ensure the details exactly match the device's reported information. ```yaml # ``` -------------------------------- ### Accessing Clusters on an Endpoint Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Example of how to access and update attributes of a specific cluster on an endpoint. ```python # Access cluster on current endpoint self.endpoint.ias_zone.update_attribute( IasZone.AttributeDefs.zone_status.id, IasZone.ZoneStatus.Alarm_1, ) ``` -------------------------------- ### Expose a Sensor Entity for Read-Only Values Source: https://github.com/zigpy/zha-device-handlers/blob/dev/CLAUDE.md Creates a sensor entity in Home Assistant to display a read-only device attribute. This example exposes the 'temperature' attribute, configuring it with optional divisor, multiplier, and HA-specific settings like device class and state class. ```python .sensor( attribute_name="temperature", cluster_id=TemperatureMeasurement.cluster_id, cluster_type=ClusterType.Server, # Optional: default Server divisor=100, # Optional: divide raw value (default 1) multiplier=1, # Optional: multiply raw value (default 1) suggested_display_precision=1, # Optional: decimal places in HA UI device_class=SensorDeviceClass.TEMPERATURE, # Optional: HA device class state_class=SensorStateClass.MEASUREMENT, # Optional: HA state class unit=UnitOfTemperature.CELSIUS, # Optional: use unit constants, not strings translation_key="temperature", fallback_name="Temperature", ) ``` -------------------------------- ### Define Custom Device with Communication Buses Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md Extend XiaomiCustomDevice and initialize Bus instances for inter-cluster communication. This setup is necessary for advanced quirk functionalities involving message passing between custom clusters. ```python class Plug(XiaomiCustomDevice): """lumi.plug.maus01 plug.""" def __init__(self, *args, **kwargs): """Init.""" self.voltage_bus = Bus() self.consumption_bus = Bus() self.power_bus = Bus() super().__init__(*args, **kwargs) ``` -------------------------------- ### V2 Quirk Definition with QuirkBuilder Source: https://github.com/zigpy/zha-device-handlers/blob/dev/CLAUDE.md Define a V2 quirk using QuirkBuilder for declarative quirk definition. This example shows basic setup including manufacturer, model, and replacing a standard cluster. ```python from zigpy.quirks.v2 import QuirkBuilder ( QuirkBuilder("Manufacturer", "Model") .applies_to("AltManufacturer", "Model") # Additional models .replaces(CustomClusterClass) # Replace standard cluster .device_automation_triggers({...}) # Button/action mappings .switch(attribute_name=..., fallback_name=...) .add_to_registry() ) ``` -------------------------------- ### Define Number Entity for Temperature Calibration with Multiplier Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md This example defines a number entity for thermostat temperature calibration, using a multiplier and step to handle fractional units represented by an integer attribute. HA-side min/max values are specified after the multiplier is applied. ```python # ZCL Thermostat local_temperature_calibration: int8s, tenths of a degree. # HA range -2.5..2.5 °C ↔ raw attribute value -25..25 .number( attribute_name=Thermostat.AttributeDefs.local_temperature_calibration.name, cluster_id=Thermostat.cluster_id, min_value=-2.5, max_value=2.5, step=0.1, multiplier=0.1, # required: pairs with step=0.1 unit=UnitOfTemperature.CELSIUS, translation_key="local_temperature_calibration", fallback_name="Local temperature calibration", ) ``` -------------------------------- ### Example Zigbee Device Quirk Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md This Python code defines a quirk for a Lumi plug device. It includes the device signature and replacement configurations for various endpoints and clusters. ```python class Plug(XiaomiCustomDevice): """lumi.plug.maus01 plug.""" def __init__(self, *args, **kwargs): """Init.""" self.voltage_bus = Bus() self.consumption_bus = Bus() self.power_bus = Bus() super().__init__(*args, **kwargs) signature = { MODELS_INFO: [(LUMI, "lumi.plug.maus01")], ENDPOINTS: { # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, PowerConfiguration.cluster_id, DeviceTemperature.cluster_id, Groups.cluster_id, Identify.cluster_id, OnOff.cluster_id, Scenes.cluster_id, BinaryOutput.cluster_id, Time.cluster_id, ElectricalMeasurement.cluster_id, ], OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id], }, # 2: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.MAIN_POWER_OUTLET, INPUT_CLUSTERS: [AnalogInput.cluster_id], OUTPUT_CLUSTERS: [AnalogInput.cluster_id, Groups.cluster_id], }, # 3: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.METER_INTERFACE, INPUT_CLUSTERS: [AnalogInput.cluster_id], OUTPUT_CLUSTERS: [AnalogInput.cluster_id], }, # 100: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR, INPUT_CLUSTERS: [BinaryInput.cluster_id], OUTPUT_CLUSTERS: [BinaryInput.cluster_id, Groups.cluster_id], }, }, } replacement = { SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ BasicCluster, PowerConfiguration.cluster_id, DeviceTemperature.cluster_id, Groups.cluster_id, Identify.cluster_id, OnOff.cluster_id, Scenes.cluster_id, BinaryOutput.cluster_id, Time.cluster_id, ElectricalMeasurementCluster, ], OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id], }, 2: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.MAIN_POWER_OUTLET, INPUT_CLUSTERS: [AnalogInputCluster], OUTPUT_CLUSTERS: [AnalogInput.cluster_id, Groups.cluster_id], }, 3: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.METER_INTERFACE, INPUT_CLUSTERS: [AnalogInput.cluster_id], OUTPUT_CLUSTERS: [AnalogInput.cluster_id], }, 100: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR, INPUT_CLUSTERS: [BinaryInput.cluster_id], OUTPUT_CLUSTERS: [BinaryInput.cluster_id, Groups.cluster_id], }, }, } ``` -------------------------------- ### Python Example for ZHA Event Data Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md This Python dictionary represents event data for a zha_event. It's used to match specific commands fired by devices, such as the 'on' command for a Hue remote. Ensure enough event data is provided to uniquely identify the event. ```python {COMMAND: COMMAND_ON} ``` -------------------------------- ### Zigpy ZNP Configuration Source: https://github.com/zigpy/zha-device-handlers/blob/dev/xbee.md Optional configuration for zigpy_znp to manage endpoint handling. This setting can be crucial for specific ZNP coordinator setups. ```yaml znp_config: prefer_endpoint_1: false ``` -------------------------------- ### Firmware Version Filtering for Quirks Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Apply a quirk only to devices with specific firmware versions, useful for handling devices with different firmware behaviors. This example targets older firmware versions. ```python # Quirk for OLD firmware (before bug was fixed) ( QuirkBuilder("innr", "SP 240") .firmware_version_filter(max_version=0x191B3685, allow_missing=False) .replaces(OldFirmwareCluster) .add_to_registry() ) ``` -------------------------------- ### Test Tuya Device Quirks Source: https://github.com/zigpy/zha-device-handlers/blob/dev/tuya.md Example test function for verifying Tuya device quirks using zigpy_device_from_v2_quirk. It checks for the presence of TuyaMCUCluster and handles data deserialization and attribute updates. ```python async def test_tuya(): """Example Tuya Test.""" quirked = zigpy_device_from_v2_quirk(model, manuf) ep = quirked.endpoints[1] temperature_listener = ClusterListener(ep.temperature) assert ep.tuya_manufacturer is not None assert isinstance(ep.tuya_manufacturer, TuyaMCUCluster) message = b"\x09\xe0\x02\x0b\x33\x01\x02\x00\x04\x00\x00\x00\xfd\x02\x02\x00\x04\x00\x00\x00\x47\x04\x02\x00\x04\x00\x00\x00\x64" hdr, data = ep.tuya_manufacturer.deserialize(message) status = ep.tuya_manufacturer.handle_get_data(data.data) assert status == foundation.Status.SUCCESS assert len(temperature_listener.attribute_updates) == 1 assert ( temperature_listener.attribute_updates[0][1] == data.data.datapoints[0].data.payload * temp_scale ) ``` -------------------------------- ### V2 Quirk Definition with QuirkBuilder Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Define a new ZHA quirk using QuirkBuilder for declarative quirk definition. This example shows basic setup, device matching, and replacing a standard cluster. ```python from zigpy.quirks.v2 import QuirkBuilder ( QuirkBuilder("Manufacturer", "Model") .applies_to("AltManufacturer", "Model") # Additional models .replaces(CustomClusterClass) # Replace standard cluster .device_automation_triggers({...}) # Button/action mappings .switch(attribute_name=..., fallback_name=...) .add_to_registry() ) ``` -------------------------------- ### v1 Tuya Quirk Example Source: https://github.com/zigpy/zha-device-handlers/wiki/Tuya-‐-v2-Quirk-with-TuyaQuirkBuilder Example of a v1 quirk definition for a Tuya device, specifying device signature and replacement endpoint configurations. ```python quirk_id = TUYA_PLUG_MANUFACTURER signature = { MODELS_INFO: [ ("_TZE200_laqjm8qd", "TS0601"), ], ENDPOINTS: { # 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaOnOffManufCluster.cluster_id, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, # 242: { PROFILE_ID: zgp.PROFILE_ID, DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, }, } replacement = { ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, INPUT_CLUSTERS: [ Basic.cluster_id, Groups.cluster_id, Scenes.cluster_id, TuyaOnOffManufCluster, TuyaOnOffNM, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 2: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, INPUT_CLUSTERS: [ TuyaOnOffNM, ], OUTPUT_CLUSTERS: [], }, 3: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, INPUT_CLUSTERS: [ TuyaOnOffNM, ], OUTPUT_CLUSTERS: [], }, 4: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, INPUT_CLUSTERS: [ TuyaOnOffNM, ], OUTPUT_CLUSTERS: [], }, 5: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, INPUT_CLUSTERS: [ TuyaOnOffNM, ], OUTPUT_CLUSTERS: [], }, 242: { PROFILE_ID: zgp.PROFILE_ID, DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, } } ``` -------------------------------- ### Load Quirk for v1 and v2 Source: https://github.com/zigpy/zha-device-handlers/blob/dev/CLAUDE.md Demonstrates how to load a quirk for testing, differentiating between v1 and v2 quirk implementations. ```python # For v1 quirks quirked = zigpy_device_from_quirk(quirk_class) # For v2 quirks quirked = zigpy_device_from_v2_quirk(model, manufacturer) ``` -------------------------------- ### Define Device Replacement Configuration Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md Use this dictionary to define how Zigpy and ZHA should interact with a specific device. Omit 'models_info' and consider 'skip_configuration' for devices that fail configuration calls. ```python replacement = { SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.SMART_PLUG, INPUT_CLUSTERS: [ BasicCluster, PowerConfiguration.cluster_id, DeviceTemperature.cluster_id, Groups.cluster_id, Identify.cluster_id, OnOff.cluster_id, Scenes.cluster_id, BinaryOutput.cluster_id, Time.cluster_id, ElectricalMeasurementCluster, ], OUTPUT_CLUSTERS: [Ota.cluster_id, Time.cluster_id], }, }, } ``` -------------------------------- ### Use Cluster References Instead of Magic Numbers Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Demonstrates the preferred way to reference cluster IDs, attribute IDs, and command IDs using their defined constants. ```python # Good - use cluster and attribute/command references Metering.cluster_id # Cluster ID (int) Metering.AttributeDefs.multiplier.id # Attribute ID (int) Metering.AttributeDefs.multiplier.name # Attribute name (str) WindowCovering.ServerCommandDefs.go_to_lift_percentage.id # Server command ID IasZone.ClientCommandDefs.status_change_notification.id # Client command ID # Bad - magic numbers 0x0702 # What cluster is this? 0x0301 # What attribute is this? 0x00 # What command is this? ``` -------------------------------- ### Define ZCL Attribute Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Example of defining a ZCL attribute with its ID, type, and manufacturer code. ```python operating_mode = ZCLAttributeDef( id=0x4007, type=BoschOperatingMode, manufacturer_code=0x1209 ) ``` -------------------------------- ### Run Pre-commit Checks Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Execute all pre-commit checks, including ruff, mypy, and codespell, across all files. ```bash pre-commit run --all-files ``` -------------------------------- ### Bash Command to Sync Dependencies Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md Use this command to synchronize your development environment with the locked dependency versions specified in the uv.lock file. This ensures consistency and reproducibility. ```bash uv sync ``` -------------------------------- ### Declarative V2 Quirk Definition Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Example of a purely declarative v2 quirk using QuirkBuilder, defining friendly name, replacing clusters, and device automation triggers. ```python ( QuirkBuilder("Manufacturer", "Model") .friendly_name(model="Wireless Mini Switch", manufacturer="Acme") .replaces(ExistingCustomCluster) .device_automation_triggers({ (SHORT_PRESS, BUTTON): {COMMAND: COMMAND_1_SINGLE}, (DOUBLE_PRESS, BUTTON): {COMMAND: COMMAND_1_DOUBLE}, }) .add_to_registry() ) ``` -------------------------------- ### Import V2 Quirk Building Utilities Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Imports classes and utilities for building v2 quirks, including QuirkBuilder and Home Assistant entity integration. ```python # Quirk building from zigpy.quirks.v2 import QuirkBuilder from zigpy.quirks.v2.homeassistant import EntityPlatform, EntityType from zigpy.quirks.v2.homeassistant import ( # Unit constants UnitOfTemperature, UnitOfTime, UnitOfEnergy, UnitOfPower, ) from zigpy.quirks.v2.homeassistant.binary_sensor import BinarySensorDeviceClass from zigpy.quirks.v2.homeassistant.number import NumberDeviceClass from zigpy.quirks.v2.homeassistant.sensor import SensorDeviceClass, SensorStateClass from zhaquirks.tuya.builder import TuyaQuirkBuilder ``` -------------------------------- ### Defining an Enum for Tuya DP and Adding to Quirk Source: https://github.com/zigpy/zha-device-handlers/wiki/Tuya-‐-v2-Quirk-with-TuyaQuirkBuilder Defines an enum for a Tuya DP and configures the quirk to use it for attribute conversion. This example sets up an irrigation mode switch. ```python class IrrigationMode(t.enum8): """Irrigation Mode Enum.""" Duration = 0x00 Capacity = 0x01 .tuya_dp_attribute( dp_id=1, attribute_name="irrigation_mode", type=t.Bool, ) .enum( ``` -------------------------------- ### Create Zigbee Device from Quirk (v1) Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Helper function to create a zigpy device instance from a v1 quirk class for testing. ```python # For v1 quirks quirked = zigpy_device_from_quirk(quirk_class) ``` -------------------------------- ### Execute ZCL Command on Button Press Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Configures a button to execute a specific ZCL command when pressed. Use for actions like factory resets. ```python .command_button( command_name="reset_to_factory_defaults", cluster_id=Basic.cluster_id, command_args=(), # Optional: positional args for command command_kwargs={}, cluster_type=ClusterType.Server, # Optional: default Server translation_key="factory_reset", fallback_name="Factory reset", ) ``` -------------------------------- ### XBee Temperature Sensor Template and Automation Source: https://github.com/zigpy/zha-device-handlers/blob/dev/xbee.md Monitor XBee temperature using a template sensor and automate periodic updates. This setup retrieves temperature readings from an XBee Pro device. ```yaml template: - trigger: - platform: event event_type: zha_event event_data: device_ieee: 00:13:a2:00:41:98:23:f9 command: tp_command_response sensor: - name: "XBee Temperature" state: '{{ trigger.event.data.args.response }}' unit_of_measurement: "°C" device_class: temperature state_class: measurement automation: - alias: Update XBee Temperature trigger: platform: time_pattern minutes: "/5" action: service: zha.issue_zigbee_cluster_command data: ieee: 00:13:a2:00:41:98:23:f9 endpoint_id: 230 command: 0x43 command_type: server cluster_type: out cluster_id: 33 params: {} ``` -------------------------------- ### Lint and Format Code Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Use ruff to check for linting issues and format the code. ```bash ruff check zhaquirks/ ruff format zhaquirks/ ``` -------------------------------- ### Create Zigbee Device from Quirk (v2) Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Helper function to create a zigpy device instance from a v2 quirk definition for testing. ```python # For v2 quirks quirked = zigpy_device_from_v2_quirk(model, manufacturer) ``` -------------------------------- ### Run Single Test File Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Execute tests within a specific file. ```bash pytest tests/test_tuya.py ``` -------------------------------- ### Import Constants for Signatures Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Imports common constants used for defining device signatures in quirks. ```python # Constants for signatures from zhaquirks.const import ( MODELS_INFO, ENDPOINTS, INPUT_CLUSTERS, OUTPUT_CLUSTERS, PROFILE_ID, DEVICE_TYPE, SKIP_CONFIGURATION, ) ``` -------------------------------- ### Run All Tests Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Execute all tests in the project using pytest. ```bash pytest tests/ ``` -------------------------------- ### CH10AX/SWITCH/1 Device Attributes and Commands Source: https://github.com/zigpy/zha-device-handlers/wiki/Schneider-Electric This snippet shows the attributes and commands for the CH10AX/SWITCH/1 device. It includes attribute definitions with their types, access levels, and values, as well as generated commands. ```json { "attributes": { "0x0000": { "attribute_id": "0x0000", "attribute_name": "device_type", "value_type": [ "0x23", "uint32_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": [ 138, 55, 9, 255, 255, 46, 33, 0 ] }, "0x0001": { "attribute_id": "0x0001", "attribute_name": "file_offset", "value_type": [ "0x23", "uint32_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 4294967295 }, "0x0002": { "attribute_id": "0x0002", "attribute_name": "current_file_version", "value_type": [ "0x23", "uint32_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 34211839 }, "0x0006": { "attribute_id": "0x0006", "attribute_name": "image_upgrade_status", "value_type": [ "0x30", "enum8", "Discrete" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 0 }, "0x0007": { "attribute_id": "0x0007", "attribute_name": "manufacturer_id", "value_type": [ "0x21", "uint16_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 4190 }, "0x0008": { "attribute_id": "0x0008", "attribute_name": "image_type_id", "value_type": [ "0x21", "uint16_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 65535 }, "0xfffd": { "attribute_id": "0xfffd", "attribute_name": "cluster_revision", "value_type": [ "0x21", "uint16_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 3 } }, "commands_received": {}, "commands_generated": { "0x01": { "command_id": "0x01", "command_name": "1", "command_args": "'not_in_zcl'" }, "0x03": { "command_id": "0x03", "command_name": "3", "command_args": "'not_in_zcl'" }, "0x06": { "command_id": "0x06", "command_name": "6", "command_args": "'not_in_zcl'" } } } ``` -------------------------------- ### Import Cluster Types and Definitions Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Imports various cluster types and specific cluster definitions from zigpy. ```python # Cluster types from zigpy.zcl import ClusterType from zigpy.zcl.clusters.general import Basic, OnOff, Groups, Scenes from zigpy.zcl.clusters.measurement import TemperatureMeasurement, RelativeHumidity import zigpy.types as t ``` -------------------------------- ### Run Specific Test Function Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Execute a particular test function within a file, with verbose output. ```bash pytest tests/test_tuya.py::test_function_name -v ``` -------------------------------- ### zha_toolkit.scan_device Output for Schneider Electric 1GANG/SHUTTER/1 Source: https://github.com/zigpy/zha-device-handlers/wiki/Schneider-Electric Displays the output from zha_toolkit.scan_device for the Schneider Electric 1GANG/SHUTTER/1, including IEEE address, network information, and detailed endpoint cluster data. ```json { "ieee": "68:0a:e2:xx:xx:xx:xx:xe", "nwk": "0xa848", "model": "1GANG/SHUTTER/1", "manufacturer": "Schneider Electric", "manufacturer_id": "0x4190", "endpoints": [ { "id": 5, "device_type": "0x0202", "profile": "0x0104", "in_clusters": { "0x0000": { "cluster_id": "0x0000", "title": "Basic", "name": "basic", "attributes": { "0x0000": { "attribute_id": "0x0000", "attribute_name": "zcl_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "READ|REPORT", "access_acl": 5, "attribute_value": 2 }, "0x0001": { "attribute_id": "0x0001", "attribute_name": "app_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "READ|REPORT", "access_acl": 5, "attribute_value": 1 }, "0x0002": { "attribute_id": "0x0002", "attribute_name": "stack_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "READ|REPORT", "access_acl": 5, "attribute_value": 5 }, "0x0003": { "attribute_id": "0x0003", "attribute_name": "hw_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "READ|REPORT", "access_acl": 5, "attribute_value": 1 }, "0x0004": { "attribute_id": "0x0004", "attribute_name": "manufacturer", "value_type": [ "0x42", "CharacterString", "Discrete" ], "access": "READ|REPORT", "access_acl": 5, "attribute_value": "Schneider Electric" }, "0x0005": { "attribute_id": "0x0005", "attribute_name": "model", "value_type": [ "0x42", "CharacterString", "Discrete" ], "access": "READ|REPORT", "access_acl": 5, "attribute_value": "1GANG/SHUTTER/1" }, "0x0006": { "attribute_id": "0x0006", "attribute_name": "date_code", "value_type": [ "0x42", "CharacterString", "Discrete" ], "access": "READ|REPORT", "access_acl": 5, "attribute_value": "" }, "0x0007": { "attribute_id": "0x0007", "attribute_name": "power_source", "value_type": [ "0x30", "enum8", ``` -------------------------------- ### Define V1 Legacy Device Quirks Source: https://github.com/zigpy/zha-device-handlers/blob/dev/CLAUDE.md V1 quirks inherit from CustomDevice and use explicit `signature` and `replacement` dictionaries. The signature must match the device exactly, and the replacement defines what ZHA should use instead. ```python from zigpy.quirks import CustomDevice from zigpy.profiles import zha from zhaquirks.const import MODELS_INFO, ENDPOINTS, INPUT_CLUSTERS from zigpy.zcl.clusters.general import Basic, OnOff class MyDevice(CustomDevice): signature = { MODELS_INFO: [("Manufacturer", "Model")], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT, INPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id], OUTPUT_CLUSTERS: [], } }, } replacement = { ENDPOINTS: { 1: { INPUT_CLUSTERS: [Basic.cluster_id, CustomOnOffCluster], } }, } ``` -------------------------------- ### Configure Number Entity for Delay Settings Source: https://github.com/zigpy/zha-device-handlers/blob/dev/CLAUDE.md Configure a number entity to represent adjustable values like delays. This snippet shows how to set minimum, maximum, step, unit, and mode for the input. ```python .number( attribute_name="off_to_on_delay", cluster_id=CustomCluster.cluster_id, cluster_type=ClusterType.Server, # Optional: default Server min_value=0, # Optional: minimum allowed value max_value=65535, # Optional: maximum allowed value step=1, # Optional: step increment unit=UnitOfTime.SECONDS, # Optional: unit constant mode="box", # Optional: "box" for text input, "slider" for slider multiplier=1, # Optional: scale between HA value and raw attribute (default 1) device_class=NumberDeviceClass.DURATION, # Optional: HA device class translation_key="turn_on_delay", fallback_name="Turn on delay", ) ``` -------------------------------- ### Type Checking Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Perform static type checking on the zhaquirks directory using mypy. ```bash mypy zhaquirks/ ``` -------------------------------- ### Define a Fully Custom Cluster Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Create a completely custom cluster for manufacturer-specific clusters that are not based on ZCL. This requires defining the cluster ID, name, and attribute definitions from scratch. ```python import zigpy.types as t from zigpy.quirks import CustomCluster from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef from typing import Final class VOCIndex(CustomCluster): """Custom cluster with no ZCL base.""" cluster_id: t.uint16_t = 0xFC7E # Manufacturer-specific cluster ID name: str = "IKEA VOC Index" ep_attribute: str = "voc_index" # Attribute name on endpoint class AttributeDefs(BaseAttributeDefs): # Note: BaseAttributeDefs, not a ZCL cluster measured_value: Final = ZCLAttributeDef( id=0x0000, type=t.Single, access="rp", manufacturer_code=0x117C ) ``` -------------------------------- ### Test Device Signature Matching Source: https://github.com/zigpy/zha-device-handlers/blob/dev/README.md Use the assert_signature_matches_quirk fixture to verify that a device signature correctly matches a ZHA quirk. This avoids the need for a full pairing process during testing. ```python def test_ts0121_signature(assert_signature_matches_quirk): signature = { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004", "0x0005", "0x0006", "0x0702", "0x0b04" ], "out_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZ3000_g5xawfcq", "model": "TS0121", "class": "zhaquirks.tuya.ts0121_plug.Plug" } assert_signature_matches_quirk(zhaquirks.tuya.ts0121_plug.Plug, signature) ``` -------------------------------- ### Configure Attribute Reporting Source: https://github.com/zigpy/zha-device-handlers/blob/dev/AGENTS.md Sets up automatic attribute reporting for a sensor. This configuration specifies the minimum and maximum intervals between reports and the minimum change required to trigger a report. ```python from zigpy.quirks.v2 import ReportingConfig .sensor( attribute_name="measured_value", cluster_id=VOCIndex.cluster_id, reporting_config=ReportingConfig( min_interval=60, # Minimum seconds between reports max_interval=120, # Maximum seconds between reports reportable_change=1, # Minimum change to trigger report ), ... ) ``` -------------------------------- ### zha_toolkit.scan_device Output for NHPB/SHUTTER/1 Source: https://github.com/zigpy/zha-device-handlers/wiki/Schneider-Electric Displays the output from zha_toolkit.scan_device for the Schneider Electric NHPB/SHUTTER/1, detailing its IEEE address, network information, and endpoint cluster attributes. This is useful for diagnosing device communication and configuration issues. ```json { "ieee": "00:3c:84:xx:xx:xx:xx:x1", "nwk": "0x21d2", "model": "NHPB/SHUTTER/1", "manufacturer": "Schneider Electric", "manufacturer_id": "0x4190", "endpoints": [ { "id": 5, "device_type": "0x0202", "profile": "0x0104", "in_clusters": { "0x0000": { "cluster_id": "0x0000", "title": "Basic", "name": "basic", "attributes": { "0x0000": { "attribute_id": "0x0000", "attribute_name": "zcl_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 3 }, "0x0001": { "attribute_id": "0x0001", "attribute_name": "app_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 2 }, "0x0002": { "attribute_id": "0x0002", "attribute_name": "stack_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 6 }, "0x0003": { "attribute_id": "0x0003", "attribute_name": "hw_version", "value_type": [ "0x20", "uint8_t", "Analog" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": 1 }, "0x0004": { "attribute_id": "0x0004", "attribute_name": "manufacturer", "value_type": [ "0x42", "CharacterString", "Discrete" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": "Schneider Electric" }, "0x0005": { "attribute_id": "0x0005", "attribute_name": "model", "value_type": [ "0x42", "CharacterString", "Discrete" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": "NHPB/SHUTTER/1" }, "0x0006": { "attribute_id": "0x0006", "attribute_name": "date_code", "value_type": [ "0x42", "CharacterString", "Discrete" ], "access": "REPORT|READ", "access_acl": 5, "attribute_value": "" }, "0x0007": { "attribute_id": "0x0007", "attribute_name": "power_source", "value_type": [ ```