zigpy / zha-device-handlers

ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
Apache License 2.0
750 stars 685 forks source link

[Device Support Request] Aqara T1 with neutral (lumi.switch.n0agl1) switch_type Support #1231

Closed alex-mikhaylov closed 1 year ago

alex-mikhaylov commented 2 years ago

Is your feature request related to a problem? Please describe. By default the Aqara's T1 with neutral (lumi.switch.n0agl1) switch_type is set to a rocker switch by default and cannot be changed via ZHA. This makes it impossible to use the switch with a momentary (push) button.

Describe the solution you'd like Making it possible to change the switch_type attribute via ZHA.

Device signature - this can be acquired by removing the device from ZHA and pairing it again from the add devices screen. Be sure to add the entire content of the log panel after pairing the device to a code block below this line.

  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4447, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *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": "0x0100",
      "in_clusters": [
        "0x0000",
        "0x0002",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0009",
        "0x000a",
        "0x0702",
        "0x0b04",
        "0xfcc0"
      ],
      "out_clusters": [
        "0x0019"
      ]
    },
    "21": {
      "profile_id": 260,
      "device_type": "0x0100",
      "in_clusters": [
        "0x000c"
      ],
      "out_clusters": []
    },
    "31": {
      "profile_id": 260,
      "device_type": "0x0100",
      "in_clusters": [
        "0x000c"
      ],
      "out_clusters": []
    },
    "41": {
      "profile_id": 260,
      "device_type": "0x0100",
      "in_clusters": [
        "0x0012"
      ],
      "out_clusters": []
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "LUMI",
  "model": "lumi.switch.n0agl1",
  "class": "zigpy.device.Device"
}

Additional context Zigbee2MQTT supports changing the switch_type - link.

Hedda commented 2 years ago

By default the Aqara's T1 with neutral (lumi.switch.n0agl1) switch_type is set to a rocker switch by default and cannot be changed via ZHA. This makes it impossible to use the switch with a momentary (push) button.

FYI, there is a similar request for "switch_type" configuration in https://github.com/zigpy/zha-device-handlers/issues/1145 for Tuya 3 gang switch TS0003 module (TZ3000_odzoiovu).

dumpfheimer mentioned you should be able to build a similar quirk using his from this other PR as a base -> https://github.com/zigpy/zha-device-handlers/pull/1391

See related developers discussion here for reference -> https://github.com/zigpy/zigpy/discussions/934

Originally posted by @dumpfheimer in https://github.com/zigpy/zigpy/discussions/934#discussioncomment-2654475

dmulcahey has been working on exposing the configuration entities here: https://github.com/dmulcahey/home-assistant/tree/dm/zha-zcl-select

Also, I have a similar PR pending here: zigpy/zha-device-handlers#1391 And I have added the necessary entites here: https://github.com/dumpfheimer/core/tree/dumpfheimer/zha-expose-configuration-entities

All three together make this setting available for Aqara H1 Switches but porting it for T1 should not be very difficult.

PS: There also looks to be a related discussion about this device in Home Assistant community forum here:

https://community.home-assistant.io/t/aqara-switch-module-t1-rebound-switch/345580/

w-marco commented 2 years ago

Any progress regarding implementation to change the switch type ? Or any way to do it manually ?

Currently my module is essentially useless because I use a momentary rocker. I am willing to test if necessary

kurtwarwick-new commented 2 years ago

I have just moved my smart home to Home Assistant with ZHA, which includes a few hundred devices. So, I was far too long into the journey before I noticed this to reasonably go back…

It would be so amazing to have this added! 😊

jrlacharnay commented 2 years ago

Waiting for it as well. This is a bit similar to this request : https://github.com/zigpy/zha-device-handlers/issues/1693

johand77 commented 2 years ago

+1 It would be very nice to have this resolved. I rather use ZHA instead of zigbee2mqtt.

kurtwarwick-new commented 2 years ago

Hi

I just wanted to post a quick update on this topic. I have become unable to wait for this option to be available "natively" through ZHA, so, I have managed to put together a custom quirk.

For those who are interested but don't know how to do that, simply do the following:

In configuration.yaml, simply add the following section:

zha:
  enable_quirks: true
  custom_quirks_path: /config/zha_quirks

Then in the config folder, create a new folder called zha_quirks.

In that new folder, add the following code snippet and restart Home Assistant.

import copy

from enum import Enum

from zigpy import types as t
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import (
    Basic,
    DeviceTemperature,
    Groups,
    Identify,
    OnOff,
    Ota,
    Scenes,
    Alarms,
    Time,
    GreenPowerProxy,
)
from zigpy.zcl.clusters.smartenergy import (
    Metering,
)
from zigpy.zcl.clusters.homeautomation import (
    ElectricalMeasurement,
)

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.xiaomi import (
    LUMI,
    XiaomiAqaraE1Cluster,
    XiaomiCustomDevice,
)

class XiaomiAqaraT1SwitchType(t.uint8_t, Enum):

    Toggle = 0x01
    Momentary = 0x02

class XiaomiAqaraT1Cluster(XiaomiAqaraE1Cluster):

    ep_attribute = "aqara_cluster"
    cluster_id = XiaomiAqaraE1Cluster.cluster_id
    attributes = {
        0x000A: ("switch_type", t.uint8_t, True)
        # 0x000A: ("switch_type", XiaomiAqaraT1SwitchType, True) - This doesn't work
    }

class AqaraSingleSwitchModelT1WithoutNeutral(XiaomiCustomDevice):
    """Aqara Single Switch Model T1 Without Neutral"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.l0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    Alarms.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id
                ]
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x00061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    Alarms.cluster_id,
                    XiaomiAqaraT1Cluster,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id
                ]
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x00061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

class AqaraSingleSwitchModelT1WithNeutral(XiaomiCustomDevice):
    """Aqara Single Switch Model T1 With Neutral"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.n0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    Metering.cluster_id,
                    ElectricalMeasurement.cluster_id,
                    XiaomiAqaraE1Cluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    OnOff.cluster_id,
                    Time.cluster_id,
                    Ota.cluster_id,
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x00061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    Metering.cluster_id,
                    ElectricalMeasurement.cluster_id,
                    XiaomiAqaraT1Cluster,
                ],
                OUTPUT_CLUSTERS: [
                    OnOff.cluster_id,
                    Time.cluster_id,
                    Ota.cluster_id,
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x00061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

That should apply the custom quirk to both the T1 with and without neutral.

image

Doing so will

  1. Expose a new cluster called XiaomiAqaraT1Cluster and an attribute called switch_type.
  2. Expose the device as a switch instead of a light.

The switch_type attribute only supports an integer value, and not an Enum as I would have preferred. This is due to an issue where I was unable to update the value. The code to support the Enum options is there, but it just doesn't work at the moment.

image

These are the errors I was getting when I tried to use the Enum:

image

I really hope that this helps ease the pain of waiting for some of you! :)

Kurt

w-marco commented 2 years ago

@kurtwarwick-new thanks for your work. I tried it with the version with neutral included and the quirk does not apply to it sadly. I copied your code and created a custom quirk (I have another custom quirk working, so it's not a config issue), but as you can see, the quirk isn't applied:

Screenshot 2022-10-10 at 11 28 35

kurtwarwick-new commented 2 years ago

Hi @w-marco

Thanks for the update! It seems that after updating to 2022.10, this quirk is no longer being applied. I am seeing the same thing.

I will need to check it out to see what the deal is! That's assuming you have updated to 2022.10.

Watch this space!

Kurt

w-marco commented 2 years ago

Hi @kurtwarwick-new, thanks for confirming. I indeed updated to 2022.10.

I’ll be looking out for a possible fix and am happy to report back if you find out what the issue is.

Thanks again!

w-marco commented 2 years ago

Hi @kurtwarwick-new just curious:

did you find a way to fix the quirk with the new version so it’s recognized again? Would be great to get this merged into official release if it’s fixed.

eesdil commented 2 years ago

I have it now "working" the "With Neutral" version. Seemingly I have 2 alternatives from it. I have two issues with it. 1) it is showing some extra electric measurement stuff, which are Unknown 2) when I switch the physical switch, it is not syncing to HA

the quirk:

import copy

from enum import Enum

from zigpy import types as t
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import (
    Basic,
    DeviceTemperature,
    Groups,
    Identify,
    OnOff,
    Ota,
    AnalogInput,
    Scenes,
    Alarms,
    Time,
    GreenPowerProxy,
    MultistateInput,
)
from zigpy.zcl.clusters.smartenergy import (
    Metering,
)
from zigpy.zcl.clusters.homeautomation import (
    ElectricalMeasurement,
)

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.xiaomi import (
    LUMI,
    XiaomiAqaraE1Cluster,
    XiaomiCustomDevice,
)

class XiaomiAqaraT1Cluster(XiaomiAqaraE1Cluster):

    ep_attribute = "aqara_cluster"
    cluster_id = XiaomiAqaraE1Cluster.cluster_id
    attributes = {
        0x000A: ("switch_type", t.uint8_t, True)
    }

class SwitchN0AGL1(XiaomiCustomDevice):
    """lumi.switch.n0agl1 switch"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.n0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    0xfcc0
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = { 
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    Metering.cluster_id,
                    ElectricalMeasurement.cluster_id,
                    XiaomiAqaraT1Cluster,
                ],
                OUTPUT_CLUSTERS: [
                    OnOff.cluster_id,
                    Time.cluster_id,
                    Ota.cluster_id,
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

class SwitchN0AGL1Alt1(SwitchN0AGL1):
    """lumi.switch.n0agl1 switch with alternative signature"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.n0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    0xfcc0
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                    0xffff
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = SwitchN0AGL1.replacement
alex-mikhaylov commented 1 year ago

Does anyone have a working quirk by any chance?

SkywiperSolutions commented 1 year ago

I have it now "working" the "With Neutral" version. Seemingly I have 2 alternatives from it. I have two issues with it.

  1. it is showing some extra electric measurement stuff, which are Unknown
  2. when I switch the physical switch, it is not syncing to HA

the quirk:

import copy

from enum import Enum

from zigpy import types as t
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import (
    Basic,
    DeviceTemperature,
    Groups,
    Identify,
    OnOff,
    Ota,
    AnalogInput,
    Scenes,
    Alarms,
    Time,
    GreenPowerProxy,
    MultistateInput,
)
from zigpy.zcl.clusters.smartenergy import (
    Metering,
)
from zigpy.zcl.clusters.homeautomation import (
    ElectricalMeasurement,
)

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.xiaomi import (
    LUMI,
    XiaomiAqaraE1Cluster,
    XiaomiCustomDevice,
)

class XiaomiAqaraT1Cluster(XiaomiAqaraE1Cluster):

    ep_attribute = "aqara_cluster"
    cluster_id = XiaomiAqaraE1Cluster.cluster_id
    attributes = {
        0x000A: ("switch_type", t.uint8_t, True)
    }

class SwitchN0AGL1(XiaomiCustomDevice):
    """lumi.switch.n0agl1 switch"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.n0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    0xfcc0
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = { 
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    Metering.cluster_id,
                    ElectricalMeasurement.cluster_id,
                    XiaomiAqaraT1Cluster,
                ],
                OUTPUT_CLUSTERS: [
                    OnOff.cluster_id,
                    Time.cluster_id,
                    Ota.cluster_id,
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

class SwitchN0AGL1Alt1(SwitchN0AGL1):
    """lumi.switch.n0agl1 switch with alternative signature"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.n0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    0xfcc0
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                    0xffff
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = SwitchN0AGL1.replacement

I tried the custom quirk and the sync when pressing the physical button works!

stoffies00711 commented 1 year ago

I have enabled and loaded the quirk. All my Aqara devices now has a quirk reference under their "device info" except this switch. What am I doing wrong?

rofo69 commented 1 year ago

There is another variant of this switch now.

I've put both device signatures here (without any quirks loaded):-

https://www.diffchecker.com/249fR60w/

The new one is on the right, and despite it only differing from the n0agl1 by having three more output clusters on endpoint 1, I'm totally failing on how to make a quirk for it. (I cant seem to get the signature right, the quirk never gets adopted by the device).

Any help appreciated to get this working!

stoffies00711 commented 1 year ago

I have given up with this switch. It's now wired into a ceiling outlet box in my passage acting only as a router/repeater with ZHA.

rofo69 commented 1 year ago

I finally figured out the solution and am leaving it here for anyone else who gets an Aqara T1 module with the same variant (lumi.switch.n0acn2).

Simply use the quirk above and change the models line from this:-

MODELS_INFO: [(LUMI, “lumi.switch.n0agl1”)],

to

MODELS_INFO: [(LUMI, “lumi.switch.n0agl1”),(LUMI, “lumi.switch.n0acn2”)],

And it starts working.!

stoffies00711 commented 1 year ago

Hey @rofo69

Edited both the main and alternate "Model" lines. Deleted the device, Restarted and Added it again. Had to physically re-plug my Zigbee dongle and finally we are moving in the right direction. The power and other sensors are either unknown or not updating after connecting a small load BUT at least now I have the Switch which now at least makes this device a little but more usable. Thank you. Does your power sensor work?

image

SkywiperSolutions commented 1 year ago

Same here. Switch can be controlled, but Active Power is 0.0 W. I still don't get why this device broke/was removed in the first place. It did work until late 2022.

rofo69 commented 1 year ago

No, I never got the power monitoring stuff working.

Bazsy commented 1 year ago

Same here. Switch is working but nothing else (power and consumption)

donjohann commented 1 year ago

Same here. Switch is working but nothing else (power and consumption)

Takacsk76 commented 1 year ago

Thanks for the solution! Unfortunately, only the switch works for me, but at least there is a switch.

ninoweg commented 1 year ago

I had to edit the replacement signature of the quirk posted by @eesdil slightly to also get data on Active Power (tested with lumi.switch.n0agl1).

import copy

from enum import Enum

from zigpy import types as t
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import (
    Basic,
    DeviceTemperature,
    Groups,
    Identify,
    OnOff,
    Ota,
    AnalogInput,
    Scenes,
    Alarms,
    Time,
    GreenPowerProxy,
    MultistateInput,
)
from zigpy.zcl.clusters.smartenergy import (
    Metering,
)
from zigpy.zcl.clusters.homeautomation import (
    ElectricalMeasurement,
)

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.xiaomi import (
    LUMI,
    XiaomiAqaraE1Cluster,
    XiaomiCustomDevice,
    BasicCluster,
    DeviceTemperatureCluster,
    XiaomiMeteringCluster,
    OnOffCluster
)

class XiaomiAqaraT1Cluster(XiaomiAqaraE1Cluster):

    ep_attribute = "aqara_cluster"
    cluster_id = XiaomiAqaraE1Cluster.cluster_id
    attributes = {
        0x000A: ("switch_type", t.uint8_t, True)
    }

class SwitchN0AGL1(XiaomiCustomDevice):
    """lumi.switch.n0agl1 switch"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.n0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    0xfcc0
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = { 
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    BasicCluster,
                    DeviceTemperatureCluster,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOffCluster,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    XiaomiMeteringCluster,
                    ElectricalMeasurement.cluster_id,
                    XiaomiAqaraT1Cluster,
                ],
                OUTPUT_CLUSTERS: [
                    OnOffCluster,
                    Time.cluster_id,
                    Ota.cluster_id,
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

class SwitchN0AGL1Alt1(SwitchN0AGL1):
    """lumi.switch.n0agl1 switch with alternative signature"""

    signature = {
        MODELS_INFO: [(LUMI, "lumi.switch.n0agl1")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DeviceTemperature.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Alarms.cluster_id,
                    Time.cluster_id,
                    0xfcc0
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                    0xffff
                ]
            },
            21: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            31: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    AnalogInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            41: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    MultistateInput.cluster_id
                ],
                OUTPUT_CLUSTERS: []
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id
                ]
            }
        }
    }

    replacement = SwitchN0AGL1.replacement
stoffies00711 commented 1 year ago

Thanks @ninoweg Will give it a go this weekend

stoffies00711 commented 1 year ago

Couldn't wait for the weekend... Copied the quirk exactly and now have an "Active Power" of 0.0 W. I connected a 12W LED light to the load but the entity does not update. Stays on zero.

chrisandsally commented 1 year ago

Hi, new to this as just got a T1 with neutral and have the same issues. Added lines in configuration.yaml. Created a directory, but what do I called the file? And File Extension?

I have just called it T1, rebooted but Quirk not loaded under Zigbee Integration.

sorry for the noob question!

stoffies00711 commented 1 year ago

Hi @chrisandsally

I got this in my yaml...

zha: enable_quirks: true custom_quirks_path: /config/zha_custom_quirks/

the last line is where I placed the file. Called it aqaralumiswitch.py I don't think the name matters, just the extension. I think ZHA will identify the device and associate the quirk.

Also a noob so I could be completely wrong here. if so, hopefully someone will correct me.

rofo69 commented 1 year ago

Correct zha doesn't care what the file is called, it decides whether or not to apply the quirk based on the signature code in the file itself. A file can have one or more signature and replacement sections.

chrisandsally commented 1 year ago

Thanks stoffies00711 and rofo69

I have checked the configuration file and quirks file now ends in .py

I removed the device, rebooted HA.

Re - added device, however quirk not showing under info and no change in Active power under load.

Screenshot 2023-06-14 at 18 39 44

stoffies00711 commented 1 year ago

Not sure. I picked up an error on my HA core logs with the quirk (") and couldn't resolve it. So I deleted the .py file and created a new one copying the quirk above exactly, removed device, rebooted HA and added it again. quirk then applied.

Takacsk76 commented 1 year ago

I tried Zigbee2mqtt on T1. It works perfectly with it. I ported 41 devices, there was only a problem with one led control type, but that was also resolved. Z2M can do more than anything and is probably being developed by more people. Overall, I like the ZHA better, but the Z2M might do better. Z2M entity handling is not good yet, but hopefully it will be fixed. The switch.devicename entity is deprecated from 2024, but neither is switch.devicename_switch. Thanks for your help. One more thing. It looks like the Chinese devices will have Z2M support by default, making them easier to implement into Z2M. Unfortunately, mqtt discovery renames the entity names and they are not imported into HA with the original entity name. I don't know what the identification is based on, but it would be nice to improve it. The ZHA is currently in a secret state, it can be restored. Sorry if I didn't write something well, but I don't speak English. Have a challenge for every day!

jrlacharnay commented 1 year ago

Hello,

I'm using ZHA and still I can't configure the switch type (toggle or push button) of my Aqara SSM-U01 (the initial problem reported).

Or did I miss something? Should I create another ticket?

Zigbee signature:

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4447, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *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": "0x0104",
      "device_type": "0x0100",
      "input_clusters": [
        "0x0000",
        "0x0002",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0009",
        "0x000a",
        "0x0702",
        "0x0b04",
        "0xfcc0"
      ],
      "output_clusters": [
        "0x0019"
      ]
    },
    "21": {
      "profile_id": "0x0104",
      "device_type": "0x0100",
      "input_clusters": [
        "0x000c"
      ],
      "output_clusters": []
    },
    "31": {
      "profile_id": "0x0104",
      "device_type": "0x0100",
      "input_clusters": [
        "0x000c"
      ],
      "output_clusters": []
    },
    "41": {
      "profile_id": "0x0104",
      "device_type": "0x0100",
      "input_clusters": [
        "0x0012"
      ],
      "output_clusters": []
    },
    "242": {
      "profile_id": "0xa1e0",
      "device_type": "0x0061",
      "input_clusters": [],
      "output_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "LUMI",
  "model": "lumi.switch.n0agl1",
  "class": "zigpy.device.Device"
}
w-marco commented 1 year ago

I also still cannot edit the switch_type with my Aqara T1.

I noticed, that the device info shows no quirk applied, even though there is one present in zhaquirks. So it looks like matching the quirk to the device doesn't work.

TheJulianJES commented 1 year ago

@jrlacharnay You can try to download the file from https://github.com/zigpy/zha-device-handlers/pull/2684 and test it as a custom quirk.

In the future, just open a new issue please. I only saw this because someone else had another alternative signature for this device.

The fix will likely only be included in Home Assistant Core 2023.12.0, as the 2023.11.x beta cut is already made (for features).

jrlacharnay commented 11 months ago

@TheJulianJES sorry for the late answer. First, big thanks for the works on this quirk. I tested, and after having re-paired my 3 T1 devices:

I'm available (and will try to answer quicker) for any additional testing.

w-marco commented 11 months ago

@jrlacharnay to change the switch type go into the device, then the three dot menu, then 'manage zigbee device'. Choose the 'OppleCluster' 0xfcc0 and then change the attribute 'swtich_type'. 1 is toggle, 2 is momentary.

as for the disconnect issues: I sporadically had that too, but also with Zigbee2MQTT so I don't think it is the quirk. I fixed it, by forcing the disconnecting devices to report their on/off status more often, thus keeping their connection alive. Ever since then, my issues disappeared. To do that using ZHA, I installed ZHA Toolkit from HACS and then issued this command under 'Developer Tools', 'Services':

service: zha_toolkit.execute
data:
  ieee: switch.XXXXX
  command: conf_report
  endpoint: 1
  cluster: 0x0006
  attribute: 0x0000
  min_interval: 5
  max_interval: 60
  tries: 100
  event_done: zha_done

Replace switch.XXX with your entity of the device that's disconnecting.

jrlacharnay commented 11 months ago

Thanks, indeed I can change the switch type with the OppleCluster.

Do you know if it's possible to have the setting displayed in the ZHA UI? Currently I only have the "start-up behavior" setting:

image

Else, all non-technical people will never find how to change the switch type.

Also, I can confirm that, as soon as I activate the quirk, the devices are very often and momentarily "unavailable". I didn't try yet the conf_report command (thanks, I didn't know ZHA toolkit!), but this is for sure not happening without the quirk.

w-marco commented 11 months ago

I talked to @TheJulianJES about displaying them in the Discord a while ago. It's certainly possible but no one came around to doing it yet. It needs to be implemented by the devs.

As fir the disconnects, that's interesting as I haven't had this, not sure what the cause could be with the Quirk. But maybe the conf_report command can fix it.

jrlacharnay commented 11 months ago

@TheJulianJES, I had the same disconnection issues after the upgrade to HA 2023.12. Removing devices and pairing them again didn't help (I was actually unable to pair them).

I don't know if I'm the only one impacted, and I didn't see any new issue reported for that, but I would suggest removing the device signature (which I posted above) from the quirk.

dumpfheimer commented 10 months ago

To be honest I have done this already but habe not come around to making a PR due to the requirements they have for PRs. Would someone want to test?

https://github.com/dumpfheimer/core/tree/dumpfheimer/zha-xiaomi-opple-configuration-entities

I have just noticed that something has changed in zhaquirks too which probably breaks this..