zha-device-handlers icon indicating copy to clipboard operation
zha-device-handlers copied to clipboard

[Device Support Request] lumi.remote.b1acn02

Open muller119 opened this issue 2 years ago • 32 comments

Problem description

lumi.remote.b1acn02 does not work in zha yet

Solution description

i dont know how to make a quirk but lumi.remote.b1acn02 is the item a aqara switch website https://zigbee.blakadder.com/Aqara_WXKG13LM.html

Screenshots/Video

Screenshots/Video

[Paste/upload your media here]

Device signature

Device signature
{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4447, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0103",
      "input_clusters": [
        "0x0000",
        "0x0001",
        "0x0003"
      ],
      "output_clusters": [
        "0x0003",
        "0x0006",
        "0x0019"
      ]
    }
  },
  "manufacturer": "LUMI",
  "model": "lumi.remote.b1acn02",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
[Paste the diagnostic information here]

Logs

Logs
[Paste the logs here]

Custom quirk

Custom quirk
[Paste your custom quirk here]

Additional information

No response

muller119 avatar Dec 07 '23 16:12 muller119

Could you share the device signature? And when you say it doesn't work, I'm assuming you're still able to join the device, just not seeing all the button presses, etc?

codyhackw avatar Dec 09 '23 16:12 codyhackw

thats correct

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4447, maximum_buffer_size=127, maximum_incoming_transfer_size=100, server_mask=11264, maximum_outgoing_transfer_size=100, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0103",
      "input_clusters": [
        "0x0000",
        "0x0001",
        "0x0003"
      ],
      "output_clusters": [
        "0x0003",
        "0x0006",
        "0x0019"
      ]
    }
  },
  "manufacturer": "LUMI",
  "model": "lumi.remote.b1acn02",
  "class": "zigpy.device.Device"
}

muller119 avatar Dec 09 '23 17:12 muller119

Are you familiar with running a custom quirk? If so, could you give this a try with the following file name? After it's applied, just restart HA and confirm there should be no errors and the device should have a quirk showing on the device page ending in "SwitchAQ3B2"

sensor_switch_aq3.py
"""Xiaomi aqara button sensor."""

from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff

from zhaquirks import CustomCluster
from zhaquirks.const import (
    COMMAND,
    COMMAND_DOUBLE,
    COMMAND_HOLD,
    COMMAND_RELEASE,
    COMMAND_SHAKE,
    COMMAND_SINGLE,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SHAKEN,
    SHORT_PRESS,
    SKIP_CONFIGURATION,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    LUMI,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiCustomDevice,
    XiaomiPowerConfiguration,
)

B1ACN01_HOLD = 0
B1ACN01_RELEASE = 255
BUTTON_DEVICE_TYPE = 0x5F01
BUTTON_DEVICE_TYPE_B = 259
DOUBLE = 2
HOLD = 16
RELEASE = 17
SHAKE = 18
SINGLE = 1
STATUS_TYPE_ATTR = 0x0055  # decimal = 85

MOVEMENT_TYPE = {
    B1ACN01_HOLD: COMMAND_HOLD,
    SINGLE: COMMAND_SINGLE,
    DOUBLE: COMMAND_DOUBLE,
    HOLD: COMMAND_HOLD,
    RELEASE: COMMAND_RELEASE,
    B1ACN01_RELEASE: COMMAND_RELEASE,
    SHAKE: COMMAND_SHAKE,
}


class MultistateInputCluster(CustomCluster, MultistateInput):
    """Multistate input cluster."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = {}
        super().__init__(*args, **kwargs)

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == STATUS_TYPE_ATTR:
            self._current_state[STATUS_TYPE_ATTR] = action = MOVEMENT_TYPE.get(value)
            event_args = {VALUE: value}
            if action is not None:
                self.listener_event(ZHA_SEND_EVENT, action, event_args)

            # show something in the sensor in HA
            super()._update_attribute(0, action)


class SwitchAQ3(XiaomiCustomDevice):
    """Aqara button device."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=24321
        # device_version=1
        # input_clusters=[0, 18, 6, 1]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.sensor_switch.aq3"), (LUMI, "lumi.sensor_swit")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    OnOff.cluster_id,
                    MultistateInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    DeviceTemperatureCluster,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE},
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 18, 3]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn01")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    MultistateInput.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B2(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 1, 3]
        # output_clusters=[3, 6, 19]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn02")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }

codyhackw avatar Dec 09 '23 18:12 codyhackw

sorry i tried to install it but it will not pick the custom one quirk i did create a python in the cache dir.

muller119 avatar Dec 09 '23 20:12 muller119

When you say you created a python in the cache dir, can you confirm what you mean?

You should have something like this in your configuration.yaml file and then a folder called "zhacustomquirks" if you're following this. Then the sensor_switch_aq3.py file goes in that folder? -

zha:
  zigpy_config:
    custom_quirks_path: /config/zhacustomquirks/

If you did that, are you seeing any errors in the logs, or can you see what quirk is being applied to the device?

codyhackw avatar Dec 09 '23 20:12 codyhackw

Knipsel Knipsel1 Knipsel2 Knipsel3 Knipsel4 Knipsel5 Knipsel6

muller119 avatar Dec 09 '23 22:12 muller119

no quirk is applied to the sensor

muller119 avatar Dec 09 '23 22:12 muller119

Alright, let's try a couple things. First off, I realized I was missing an import in the original file, so if you could swap it out for this we should be good -

sensor_switch_aq3.py
"""Xiaomi aqara button sensor."""

from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff, PowerConfiguration

from zhaquirks import CustomCluster
from zhaquirks.const import (
    COMMAND,
    COMMAND_DOUBLE,
    COMMAND_HOLD,
    COMMAND_RELEASE,
    COMMAND_SHAKE,
    COMMAND_SINGLE,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SHAKEN,
    SHORT_PRESS,
    SKIP_CONFIGURATION,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    LUMI,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiCustomDevice,
    XiaomiPowerConfiguration,
)

B1ACN01_HOLD = 0
B1ACN01_RELEASE = 255
BUTTON_DEVICE_TYPE = 0x5F01
BUTTON_DEVICE_TYPE_B = 259
DOUBLE = 2
HOLD = 16
RELEASE = 17
SHAKE = 18
SINGLE = 1
STATUS_TYPE_ATTR = 0x0055  # decimal = 85

MOVEMENT_TYPE = {
    B1ACN01_HOLD: COMMAND_HOLD,
    SINGLE: COMMAND_SINGLE,
    DOUBLE: COMMAND_DOUBLE,
    HOLD: COMMAND_HOLD,
    RELEASE: COMMAND_RELEASE,
    B1ACN01_RELEASE: COMMAND_RELEASE,
    SHAKE: COMMAND_SHAKE,
}


class MultistateInputCluster(CustomCluster, MultistateInput):
    """Multistate input cluster."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = {}
        super().__init__(*args, **kwargs)

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == STATUS_TYPE_ATTR:
            self._current_state[STATUS_TYPE_ATTR] = action = MOVEMENT_TYPE.get(value)
            event_args = {VALUE: value}
            if action is not None:
                self.listener_event(ZHA_SEND_EVENT, action, event_args)

            # show something in the sensor in HA
            super()._update_attribute(0, action)


class SwitchAQ3(XiaomiCustomDevice):
    """Aqara button device."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=24321
        # device_version=1
        # input_clusters=[0, 18, 6, 1]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.sensor_switch.aq3"), (LUMI, "lumi.sensor_swit")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    OnOff.cluster_id,
                    MultistateInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    DeviceTemperatureCluster,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE},
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 18, 3]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn01")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    MultistateInput.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B2(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 1, 3]
        # output_clusters=[3, 6, 19]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn02")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }

^Also when you replace that file, could you delete the pycache folder and let it repopulate?

Second, could you please add this to your configuration.yaml? -

logger:
  default: info
  logs:
    homeassistant.components.zha: debug
    zigpy: debug

Is that 0xD4CF device the device in question? If so, can you restart with the debug logs and search for that device in the logs and see what comes up?

codyhackw avatar Dec 09 '23 22:12 codyhackw

Thank you, that's very helpful! I want to confirm a couple things that I believe I'm seeing in the logs though. It looks like you removed/readded the device after restarting, and it came back with a Network ID of 0x3A43, is that right? (should see it on the device page as 'Nwk: 0x3A43' under Zigbee Info)

If that's the case, let's add the following file to your custom quirk folder as well (note 2 underscores on each side for the init file), and replace the custom quirk with the updated file below and repeat the delete __pycache__ folder and restart with debug logs again please -

__init__.py
"""Module for Xiaomi Aqara quirks implementations."""
sensor_switch_aq3.py
"""Xiaomi aqara button sensor."""

from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff

from zhaquirks import CustomCluster
from zhaquirks.const import (
    COMMAND,
    COMMAND_DOUBLE,
    COMMAND_HOLD,
    COMMAND_RELEASE,
    COMMAND_SHAKE,
    COMMAND_SINGLE,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SHAKEN,
    SHORT_PRESS,
    SKIP_CONFIGURATION,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    LUMI,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiCustomDevice,
    XiaomiPowerConfiguration,
)

B1ACN01_HOLD = 0
B1ACN01_RELEASE = 255
BUTTON_DEVICE_TYPE = 0x5F01
BUTTON_DEVICE_TYPE_B = 259
DOUBLE = 2
HOLD = 16
RELEASE = 17
SHAKE = 18
SINGLE = 1
STATUS_TYPE_ATTR = 0x0055  # decimal = 85

MOVEMENT_TYPE = {
    B1ACN01_HOLD: COMMAND_HOLD,
    SINGLE: COMMAND_SINGLE,
    DOUBLE: COMMAND_DOUBLE,
    HOLD: COMMAND_HOLD,
    RELEASE: COMMAND_RELEASE,
    B1ACN01_RELEASE: COMMAND_RELEASE,
    SHAKE: COMMAND_SHAKE,
}


class MultistateInputCluster(CustomCluster, MultistateInput):
    """Multistate input cluster."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = {}
        super().__init__(*args, **kwargs)

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == STATUS_TYPE_ATTR:
            self._current_state[STATUS_TYPE_ATTR] = action = MOVEMENT_TYPE.get(value)
            event_args = {VALUE: value}
            if action is not None:
                self.listener_event(ZHA_SEND_EVENT, action, event_args)

            # show something in the sensor in HA
            super()._update_attribute(0, action)


class SwitchAQ3(XiaomiCustomDevice):
    """Aqara button device."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=24321
        # device_version=1
        # input_clusters=[0, 18, 6, 1]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.sensor_switch.aq3"), (LUMI, "lumi.sensor_swit")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    OnOff.cluster_id,
                    MultistateInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    DeviceTemperatureCluster,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE},
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 18, 3]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn01")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    MultistateInput.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B2(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 1, 3]
        # output_clusters=[3, 6, 19]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn02")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }

codyhackw avatar Dec 10 '23 02:12 codyhackw

i ran some tests first off all i want to make sure that the line in configuration line is ok

zha: zigpy_config: custom_quirks_path: /config/zhacustomquirks/

it doenst create the PYCACHE folder

when i does this line

zha: custom_quirks_path: /config/zhacustomquirks/

it does create the folder PYCACHE folde

whats is the expected reaction?

i tried both methods without any succes,

home-assistant_zha_2023-12-10T09-52-01.289Z.log home-assistant_zha_2023-12-10T09-51-02.274Z.log home-assistant_zha_2023-12-10T09-38-40.638Z.log home-assistant_zha_2023-12-10T09-12-22.082Z.log

the latest log is with init with the without the zigpy_config line

muller119 avatar Dec 10 '23 10:12 muller119

I'm so sorry, I see in the example I gave I had it indented after zigpy_config, that's not right. You'll definitely want it under zha like so (using your folder name) -

zha:
  custom_quirks_path: /config/custom_zha_quirks/

Even with that, I'm not seeing your device pull the custom quirk. Can you confirm from the device page, are you seeing battery information, etc? It appears from the logs like that's all being reported, but trying to make sure I'm on the same page with what is and isn't working for you.

@TheJulianJES does anything stand out to you here (see you worked on some of the other Aqara devices recently)? I'm pretty sure I'll need to add the OppleCluster to the replacement based on:

[zigpy.device] [0xb037] Ignoring message on unknown cluster 64704 for endpoint <Endpoint id=1 in=[basic:0x0000, identify:0x0003, power:0x0001] out=[identify:0x0003, ota:0x0019, on_off:0x0006] status=<Status.ZDO_INIT: 1>>

But I would've expected to at least see the quirk applied at this point and just still had that error in the logs?

codyhackw avatar Dec 10 '23 16:12 codyhackw

Knipsel11 its not picking the custom one

i will try it one more time

muller119 avatar Dec 10 '23 16:12 muller119

this was last my last test the logs below

netwerk code for the device is 0xd8e7 home-assistant_zha_2023-12-10T16-41-25.725Z.log

muller119 avatar Dec 10 '23 16:12 muller119

i tested somethings on my own in the end i had an error on the custom quirk that the ota was not defined after deleted the line it started up warning that the custom quirk was loaded.

but after adding the device nothing changed

but in the logs when i pressed the buttons it reacted maybe some more info for you

network code :0x998f home-assistant_zha_2023-12-16T22-16-39.696Z.log

muller119 avatar Dec 16 '23 22:12 muller119

Can you share what ended up working for you to get the quirk applied?

codyhackw avatar Dec 17 '23 03:12 codyhackw

here is the code i used it did pickup by HA but not by the device i think doesnt show up at the device page if its uses a quirk

so what i did is deleted the 2 lines it says ota cluster id

"""Xiaomi aqara button sensor."""

from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff

from zhaquirks import CustomCluster
from zhaquirks.const import (
    COMMAND,
    COMMAND_DOUBLE,
    COMMAND_HOLD,
    COMMAND_RELEASE,
    COMMAND_SHAKE,
    COMMAND_SINGLE,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SHAKEN,
    SHORT_PRESS,
    SKIP_CONFIGURATION,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    LUMI,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiCustomDevice,
    XiaomiPowerConfiguration,
)

B1ACN01_HOLD = 0
B1ACN01_RELEASE = 255
BUTTON_DEVICE_TYPE = 0x5F01
BUTTON_DEVICE_TYPE_B = 259
DOUBLE = 2
HOLD = 16
RELEASE = 17
SHAKE = 18
SINGLE = 1
STATUS_TYPE_ATTR = 0x0055  # decimal = 85

MOVEMENT_TYPE = {
    B1ACN01_HOLD: COMMAND_HOLD,
    SINGLE: COMMAND_SINGLE,
    DOUBLE: COMMAND_DOUBLE,
    HOLD: COMMAND_HOLD,
    RELEASE: COMMAND_RELEASE,
    B1ACN01_RELEASE: COMMAND_RELEASE,
    SHAKE: COMMAND_SHAKE,
}


class MultistateInputCluster(CustomCluster, MultistateInput):
    """Multistate input cluster."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = {}
        super().__init__(*args, **kwargs)

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == STATUS_TYPE_ATTR:
            self._current_state[STATUS_TYPE_ATTR] = action = MOVEMENT_TYPE.get(value)
            event_args = {VALUE: value}
            if action is not None:
                self.listener_event(ZHA_SEND_EVENT, action, event_args)

            # show something in the sensor in HA
            super()._update_attribute(0, action)


class SwitchAQ3(XiaomiCustomDevice):
    """Aqara button device."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=24321
        # device_version=1
        # input_clusters=[0, 18, 6, 1]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.sensor_switch.aq3"), (LUMI, "lumi.sensor_swit")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    OnOff.cluster_id,
                    MultistateInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    DeviceTemperatureCluster,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE},
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 18, 3]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn01")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    MultistateInput.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B2(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 1, 3]
        # output_clusters=[3, 6, 19]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn02")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                ],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                ],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }

muller119 avatar Dec 17 '23 09:12 muller119

i was doing some more logging and testeing until i saw this

Checking quirks for LUMI lumi.remote.b1acn02 (54:ef:44:10:00:92:45:22) Considering <class 'sensor_switch_aq3.SwitchAQ3B2'> Fail because output cluster mismatch on at least one endpoint

so thougt i added the OTA again

"""Xiaomi aqara button sensor."""

from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff, Ota

from zhaquirks import CustomCluster
from zhaquirks.const import (
    COMMAND,
    COMMAND_DOUBLE,
    COMMAND_HOLD,
    COMMAND_RELEASE,
    COMMAND_SHAKE,
    COMMAND_SINGLE,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SHAKEN,
    SHORT_PRESS,
    SKIP_CONFIGURATION,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    LUMI,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiCustomDevice,
    XiaomiPowerConfiguration,
)

B1ACN01_HOLD = 0
B1ACN01_RELEASE = 255
BUTTON_DEVICE_TYPE = 0x5F01
BUTTON_DEVICE_TYPE_B = 259
DOUBLE = 2
HOLD = 16
RELEASE = 17
SHAKE = 18
SINGLE = 1
STATUS_TYPE_ATTR = 0x0055  # decimal = 85

MOVEMENT_TYPE = {
    B1ACN01_HOLD: COMMAND_HOLD,
    SINGLE: COMMAND_SINGLE,
    DOUBLE: COMMAND_DOUBLE,
    HOLD: COMMAND_HOLD,
    RELEASE: COMMAND_RELEASE,
    B1ACN01_RELEASE: COMMAND_RELEASE,
    SHAKE: COMMAND_SHAKE,
}


class MultistateInputCluster(CustomCluster, MultistateInput):
    """Multistate input cluster."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = {}
        super().__init__(*args, **kwargs)

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == STATUS_TYPE_ATTR:
            self._current_state[STATUS_TYPE_ATTR] = action = MOVEMENT_TYPE.get(value)
            event_args = {VALUE: value}
            if action is not None:
                self.listener_event(ZHA_SEND_EVENT, action, event_args)

            # show something in the sensor in HA
            super()._update_attribute(0, action)


class SwitchAQ3(XiaomiCustomDevice):
    """Aqara button device."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=24321
        # device_version=1
        # input_clusters=[0, 18, 6, 1]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.sensor_switch.aq3"), (LUMI, "lumi.sensor_swit")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    OnOff.cluster_id,
                    MultistateInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    DeviceTemperatureCluster,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE},
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 18, 3]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn01")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    MultistateInput.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B2(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 1, 3]
        # output_clusters=[3, 6, 19]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn02")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }

and it get picked up by ZHA but stil the same error thats why it skips the quirk i think

muller119 avatar Dec 17 '23 20:12 muller119

So just to clarify, in both scenarios, you don't see the quirk applied on the device page? It should look more like this (the first portion being the file name, so in your case I expect "sensor_switch_aq3.SwitchAQ3B2") - image

Compared to the built-in quirks - image

Where did you order this by chance? I've got the previous b1acn01, but not seeing where this is available currently.

codyhackw avatar Dec 18 '23 00:12 codyhackw

nope

so i have also the öld"one its works fine

Knipsel20

and this one is the problem so far

Knipsel21

i bought it here

https://www.hashop.nl/aqara-wireless-mini-switch-t1

i believe its the next gen i have also have those but then of the magnets ones

this is the quirk its used by the magnegts fot the door switches zhaquirks.xiaomi.aqara.magnet_agl02.MagnetT1

muller119 avatar Dec 18 '23 05:12 muller119

You got this fixed i got the same issue?

JasperLefever avatar Dec 21 '23 20:12 JasperLefever

does anything stand out to you here (see you worked on some of the other Aqara devices recently)? I'm pretty sure I'll need to add the OppleCluster to the replacement based on [...] But I would've expected to at least see the quirk applied at this point and just still had that error in the logs?

Yeah, looks like the OppleCluster needs to be added to the replacement. If your quirk isn't matching, there should be some more information in ZHA debug logs. You can also try to use this tool to generate a "stub quirk" (signature part) from the device signature or device diagnostics: https://github.com/zigpy/quirk-generator

Also, some Xiaomi devices report a different signature when they're re-paired. It's a firmware issue. It should be the same replacement for "all devices that are the same".

Lastly, if the code is somewhat ready, please create a PR. If you need help, let me know. I sometimes miss mentions in issues though, as I get a lot of them. I should see PRs though (or if you mention me multiple times).

TheJulianJES avatar Dec 24 '23 04:12 TheJulianJES

I'm so sorry, I see in the example I gave I had it indented after zigpy_config, that's not right. You'll definitely want it under zha like so (using your folder name) -

zha:
  custom_quirks_path: /config/custom_zha_quirks/

Even with that, I'm not seeing your device pull the custom quirk. Can you confirm from the device page, are you seeing battery information, etc? It appears from the logs like that's all being reported, but trying to make sure I'm on the same page with what is and isn't working for you.

@TheJulianJES does anything stand out to you here (see you worked on some of the other Aqara devices recently)? I'm pretty sure I'll need to add the OppleCluster to the replacement based on:

[zigpy.device] [0xb037] Ignoring message on unknown cluster 64704 for endpoint <Endpoint id=1 in=[basic:0x0000, identify:0x0003, power:0x0001] out=[identify:0x0003, ota:0x0019, on_off:0x0006] status=<Status.ZDO_INIT: 1>>

But I would've expected to at least see the quirk applied at this point and just still had that error in the logs?

other times its says cluster 18

muller119 avatar Dec 24 '23 17:12 muller119

I got the quirk to be applied by adding Ota to the imports up top.

Currently trying to get the button presses to work but no luck so far. I do see the packet ignored message too. Mine looks like this:

[0x4eda] Ignoring message on unknown cluster 18 for endpoint <CustomEndpoint id=1 in=[basic:0x0000, power:0x0001, identify:0x0003] out=[identify:0x0003, on_off:0x0006, ota:0x0019] status=<Status.ZDO_INIT: 1>>

@TheJulianJES When you say the OppleCluster needs to be added to the replacement, does that mean that it should be added to the list of replacements or does it replace one of the in/outputs?

edit: looks like it should be in the replacement's input list. Is there one that currently exists that should work or is writing a correct cluster from scratch needed?

donnywals avatar Dec 28 '23 19:12 donnywals

I got the quirk to be applied by adding Ota to the imports up top.

Currently trying to get the button presses to work but no luck so far. I do see the packet ignored message too. Mine looks like this:

[0x4eda] Ignoring message on unknown cluster 18 for endpoint <CustomEndpoint id=1 in=[basic:0x0000, power:0x0001, identify:0x0003] out=[identify:0x0003, on_off:0x0006, ota:0x0019] status=<Status.ZDO_INIT: 1>>

@TheJulianJES When you say the OppleCluster needs to be added to the replacement, does that mean that it should be added to the list of replacements or does it replace one of the in/outputs?

edit: looks like it should be in the replacement's input list. Is there one that currently exists that should work or is writing a correct cluster from scratch needed?

@donnywals can you share youre quirk?? then i can test it too if its picking it up

muller119 avatar Dec 28 '23 20:12 muller119

Sure thing! This one worked for me (to get it to be picked up)

"""Xiaomi aqara button sensor."""

from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff, Ota

from zhaquirks import CustomCluster
from zhaquirks.const import (
    COMMAND,
    COMMAND_DOUBLE,
    COMMAND_HOLD,
    COMMAND_RELEASE,
    COMMAND_SHAKE,
    COMMAND_SINGLE,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SHAKEN,
    SHORT_PRESS,
    SKIP_CONFIGURATION,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    LUMI,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiCustomDevice,
    XiaomiPowerConfiguration,
)

B1ACN01_HOLD = 0
B1ACN01_RELEASE = 255
BUTTON_DEVICE_TYPE = 0x5F01
BUTTON_DEVICE_TYPE_B = 259
DOUBLE = 2
HOLD = 16
RELEASE = 17
SHAKE = 18
SINGLE = 1
STATUS_TYPE_ATTR = 0x0055  # decimal = 85

MOVEMENT_TYPE = {
    B1ACN01_HOLD: COMMAND_HOLD,
    SINGLE: COMMAND_SINGLE,
    DOUBLE: COMMAND_DOUBLE,
    HOLD: COMMAND_HOLD,
    RELEASE: COMMAND_RELEASE,
    B1ACN01_RELEASE: COMMAND_RELEASE,
    SHAKE: COMMAND_SHAKE,
}


class MultistateInputCluster(CustomCluster, MultistateInput):
    """Multistate input cluster."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = {}
        super().__init__(*args, **kwargs)

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == STATUS_TYPE_ATTR:
            self._current_state[STATUS_TYPE_ATTR] = action = MOVEMENT_TYPE.get(value)
            event_args = {VALUE: value}
            if action is not None:
                self.listener_event(ZHA_SEND_EVENT, action, event_args)

            # show something in the sensor in HA
            super()._update_attribute(0, action)


class SwitchAQ3(XiaomiCustomDevice):
    """Aqara button device."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=24321
        # device_version=1
        # input_clusters=[0, 18, 6, 1]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.sensor_switch.aq3"), (LUMI, "lumi.sensor_swit")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    OnOff.cluster_id,
                    MultistateInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    DeviceTemperatureCluster,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE},
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 18, 3]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn01")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    MultistateInput.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B2(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 1, 3]
        # output_clusters=[3, 6, 19]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn02")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }

donnywals avatar Dec 28 '23 20:12 donnywals

ok i got it somewhat working maybe it have to be cleaned up but the button presses is working and al;so the battery i am not sure if all the button presses is ok i dont know if its support long press or 3x press but for now it works' @donnywals can you test it too?

"""Xiaomi aqara button sensor."""

from zigpy.profiles import zha
from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff, Ota
import zigpy.types as types

from zhaquirks import CustomCluster
from zhaquirks.const import (
    COMMAND,
    COMMAND_DOUBLE,
    COMMAND_HOLD,
    COMMAND_RELEASE,
    COMMAND_SHAKE,
    COMMAND_SINGLE,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
    SHAKEN,
    SHORT_PRESS,
    SKIP_CONFIGURATION,
    VALUE,
    ZHA_SEND_EVENT,
)
from zhaquirks.xiaomi import (
    LUMI,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiCustomDevice,
    XiaomiPowerConfiguration,
    XiaomiAqaraE1Cluster,
)

B1ACN01_HOLD = 0
B1ACN01_RELEASE = 255
BUTTON_DEVICE_TYPE = 0x5F01
BUTTON_DEVICE_TYPE_B = 259
DOUBLE = 2
HOLD = 16
RELEASE = 17
SHAKE = 18
SINGLE = 1
STATUS_TYPE_ATTR = 0x0055  # decimal = 85

MOVEMENT_TYPE = {
    B1ACN01_HOLD: COMMAND_HOLD,
    SINGLE: COMMAND_SINGLE,
    DOUBLE: COMMAND_DOUBLE,
    HOLD: COMMAND_HOLD,
    RELEASE: COMMAND_RELEASE,
    B1ACN01_RELEASE: COMMAND_RELEASE,
    SHAKE: COMMAND_SHAKE,
}


class OppleCluster(XiaomiAqaraE1Cluster):
    """Opple cluster."""

    attributes = {
        0x0009: ("mode", types.uint8_t, True),
    }
    attr_config = {0x0009: 0x01}

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = None
        super().__init__(*args, **kwargs)

    async def bind(self):
        """Bind cluster."""
        result = await super().bind()
        await self.write_attributes(self.attr_config, manufacturer=OPPLE_MFG_CODE)
        return result

class MultistateInputCluster(CustomCluster, MultistateInput):
    """Multistate input cluster."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self._current_state = {}
        super().__init__(*args, **kwargs)

    def _update_attribute(self, attrid, value):
        super()._update_attribute(attrid, value)
        if attrid == STATUS_TYPE_ATTR:
            self._current_state[STATUS_TYPE_ATTR] = action = MOVEMENT_TYPE.get(value)
            event_args = {VALUE: value}
            if action is not None:
                self.listener_event(ZHA_SEND_EVENT, action, event_args)

            # show something in the sensor in HA
            super()._update_attribute(0, action)


class SwitchAQ3(XiaomiCustomDevice):
    """Aqara button device."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=24321
        # device_version=1
        # input_clusters=[0, 18, 6, 1]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.sensor_switch.aq3"), (LUMI, "lumi.sensor_swit")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    OnOff.cluster_id,
                    MultistateInput.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    DeviceTemperatureCluster,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE},
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 18, 3]
        # output_clusters=[0]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn01")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    MultistateInput.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    MultistateInputCluster,
                ],
                OUTPUT_CLUSTERS: [Basic.cluster_id],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }


class SwitchAQ3B2(XiaomiCustomDevice):
    """Aqara button device - alternate version."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=259
        # device_version=1
        # input_clusters=[0, 1, 3]
        # output_clusters=[3, 6, 19]>
        MODELS_INFO: [(LUMI, "lumi.remote.b1acn02")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: BUTTON_DEVICE_TYPE_B,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    XiaomiPowerConfiguration.cluster_id,
                    Identify.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }
    replacement = {
        SKIP_CONFIGURATION: True,
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    XiaomiPowerConfiguration,
                    Identify.cluster_id,
                    MultistateInputCluster,
                    OppleCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    Ota.cluster_id,
                    OppleCluster,
                ],
            }
        },
    }

    device_automation_triggers = {
        (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE},
        (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE},
        (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD},
        (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE},
    }

muller119 avatar Dec 28 '23 21:12 muller119

now we need to add the button presses i saw tripple = 3 but how i can i add these in the code i saw the following codes for now

B1ACN01_HOLD = 0 single =1 double =2 tripple =3 quintuple = 5 B1ACN01_RELEASE = 255 many presses = 6

i think these are the button presses accoording https://zigbee.blakadder.com/Aqara_WXKG13LM.html i saw these numbers in the logs when i pressed these

muller119 avatar Dec 29 '23 09:12 muller119

@TheJulianJES i did a pr https://github.com/zigpy/zha-device-handlers/pull/2871

muller119 avatar Dec 29 '23 14:12 muller119

@muller119 @donnywals just wanted to say thank you for putting in the effort to get this working & share the result with all of us :)

danroozemond avatar Dec 29 '23 19:12 danroozemond