Manually setting 'backlight' attribute on Zigbee MOES Tuya lightswitch with ZHA toolkit (TS0014)

I have a MOES Tuya lightswitch that is detected as ‘generic device’ in ZHA. Supposedly, it should have backlight, but it seems it can only be enabled trough the app. I can see that ZHA supports other similar devices, so I’m trying to simply find and set the right attribute.
(I’m really new to all HA stuff, maybe 10-15hrs in in total, but not new to programming, tinkering with phone firmwares etc, so I kinda have a vague idea of what I’m doing)

From what I understand this device is not supported in ZHA directly, but as a generic lightswitch it works fine, all buttons trigger both ways (to and from the dashboard) and I was able to do a few automations between a couple of these switches.

To find out what the backlight might be I had a look at ZHA device handles source code and I can see that it’s supposed to be cluster 6 (on_off) attribute 0x8001.

class TuyaZBOnOffAttributeCluster(TuyaEnchantableCluster, OnOff):
    """Tuya Zigbee On Off cluster with extra attributes."""

    attributes = OnOff.attributes.copy()
    attributes.update({0x8000: ("child_lock", t.Bool)})
    attributes.update({0x8001: ("backlight_mode", SwitchBackLight)})
    attributes.update({0x8002: ("power_on_state", PowerOnState)})
    attributes.update({0x8004: ("switch_mode", SwitchMode)})

https://github.com/zigpy/zha-device-handlers/blob/4ea1668256396cf2254cd32a40bf785e698de6bd/zhaquirks/tuya/__init__.py#L966

I did a scan on the device with the toolkit and I can see the general structure is quite as I’d expect with 0x8001 and 0x8002 attributes where they are supposed to be as far as I understand.
However, when I read 0x8001 attribute it’s already set to 1 (on every button of every switch), which is somewhat suspicious. Also when I write pretty much anything into that attribute nothing happens.

I did confirm with the read that the write was successful, and writing directly into on_off attribute triggered the switch so writing seems to work fine, just the value itself doesn’t seem to trigger anything.
Is there a trick to writing those values, or should I be doing something extra after pushing the value in, idk, some sort of ‘commit’?

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=4098, 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=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": "0x0100",
      "input_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "2": {
      "profile_id": "0x0104",
      "device_type": "0x0100",
      "input_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "output_clusters": []
    },
    "3": {
      "profile_id": "0x0104",
      "device_type": "0x0100",
      "input_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "output_clusters": []
    },
    "4": {
      "profile_id": "0x0104",
      "device_type": "0x0100",
      "input_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "output_clusters": []
    },
    "242": {
      "profile_id": "0xa1e0",
      "device_type": "0x0061",
      "input_clusters": [],
      "output_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZ3000_mrduubod",
  "model": "TS0014",
  "class": "zigpy.device.Device"
}

Snippet from the full scan:

            "0x8001": {
              "attribute_id": "0x8001",
              "attribute_name": "32769",
              "value_type": [
                "0x30",
                "enum8",
                "Discrete"
              ],
              "access": "REPORT|WRITE|READ",
              "access_acl": 7,
              "attribute_value": 1
            },
            "0x8002": {
              "attribute_id": "0x8002",
              "attribute_name": "32770",
              "value_type": [
                "0x30",
                "enum8",
                "Discrete"
              ],
              "access": "REPORT|WRITE|READ",
              "access_acl": 7,
              "attribute_value": 0

I pulled a quirk for a similar switch from github, adjusted the parameters to fit mine, and was able to make ZHA recognize the quirk and pick it up.
The only difference I noticed though was that in the “manage zigbee device” there were specific names to the clusters and attributes. No new menus appeared.

Also when I read the attribute using the dev toolkit instead of generic data
‘2023-05-27T13:57:34.077708+00:00,On/Off,32769,enum8.undefined_0x01,0x8001,0x0006,1,70:ac:08:ff:fe:04:a4:e3,0x30’

I now see

‘2023-05-28T16:23:05.791366+00:00,On/Off,backlight_mode,SwitchBackLight.Mode_1,0x8001,0x0006,1,70:ac:08:ff:fe:04:a4:e3,0x30’

The attributes now have specific names (including backlight) but there is still no visible way to change it trough the dashboard.
Even the ‘read attribute’ doesn’t work when executed from ZHA ‘manage zigbee device’ - it just thinks for a while and shows an error symbol.
I can still use the dev toolkit but something clearly isn’t working correctly.

For posterity:
The ‘backlight’ on this switch is operated by the regular button light. The cluster 6, 0x8001 is the correct address indeed.
The default value is 1 - ‘normal mode’, button light is off when the state if ‘off’ and on when the state is ‘on’, as you would normally expect.
There is also 0 - ‘silent mode’, when button light is always off (even when the state if ‘on’).
And there is 2 - ‘reverse mode’, opposite to ‘1’, button light is on when the state if ‘off’ and off when the state is ‘on’.

These can be set individually through dev toolkit.
MQTT supports these switches better, all extra ‘features’ have separate entities and can be added to the dashboard.

Thanks - this was useful. I was able to turn the back light on when the light is switched off.
Just changed the number to ‘2’ as per your notes above. It’s a challenge in the dark when it’s a 3-gang switch.

@stsilver Are you saying that if I use MQTT, I could dynamically control when the LEDs are on/off?
An example use case might be in a bed room:

as a sleeping person, I want the LEDs to be off so that I can sleep - until I get up and my motion is detected by a motion sensor then the LEDs turn on so I can find the light switch.

Yep, you should be able to do that no problem. :+1:
In MQTT the backlight is a regular attribute and can be changed both on dashboard and through automations.

Although the backlight on that particular light switch is not too bright, not at all like LEDs on some laptop chargers that seem to blind you no matter whether your eyes are open or closed. :slight_smile:

I bought one of those Moes Zigbee wall switch to replace my current Wifi shitches and I was unhappy with this one’s button lights always off. Thanks to your tips I managed to have the button lights always on.
What I am not happy with is that is that the other wall switches I have are blue when off and red when on, this one seems to have only one color (Blue) that is either on or off. This means that in the night in one of the 2 state you’ll not see the button well.

Isn’t there a mode to have 2 colors ? Does this has only one color by hardware ?

OT: I would love to have those wall switches to have the button color RGB so that we can use the button color also as an home notification for something (or for cosmetic, you can color the buttons whatever you want)

Nah, I was disappointed too, there is only a ‘normal backlight’ mode, ‘reverse backlight’ mode, and ‘no backlight mode’, all with the same blue light color.

Great article, I have a couple of these switches but was going to replace them and look for something with a working backlight mode, this article solved that problem for me. Now I am ready to order several more in my ongoing automation project with HA.