Help with Homey & OXT RGBCCT Zigbee Controller (ts0502B) — Basic Controls Not Working

Hey everyone,

I’m reaching out for advice on integrating a Zigbee LED controller into my Homey setup. The device in question is the OXT LED RGBCCT 12‑24 V SD Zigbee+RF Hue Tuya (model LC031)—you might also see it referred to as “ts0502B” or by its manufacturer identifier “_TZB210_nfzrlz29.”

Here’s what’s happening:

  • Homey recognizes it as a “Generic Zigbee device,” which is promising.

  • But unfortunately, even the simplest functions—on/off control and dimming—don’t work at all.

To be precise, when doing on/off in homey app - the small led on controler blinks - so it receives the signal.

I’ve tried removing and re-pairing the device, and even restarting it, but nothing changes.

Has anyone successfully integrated this exact controller (or a similar one) with Homey?

Also curious if there’s a better driver or zigbee app I could try that’s known to support ts0502B or this type of RGBCCT controller.

Thanks so much for any help.
Link: Tuya - RGBW+CCT 5in1 LED strip and ribbon controller - ZigBee/RF SD - Android/iOS app - OXT LC031 Botland - Robotic Shop

Bumping this.

After not even waiting a day?

After few repairing on/off started working.
Trying to do the dim, kind of breaks the flow, and on/off stops working for a few mins. And works back afterwards.

Those are issues that an app is most likely not able to fix, as they sound like low-level Zigbee issues. Apps only have (very) high-level access to Zigbee, all the rest is handled by Homey itself.

I was able to capture the issue. On the video, I change the on off values in dev tools, and after changing the dim value it crashes.

Attaching the video:

LinkLink

Time to find a better controller :man_shrugging:t3:

I won’t give up that easily lol! After troubleshooting I found out it actually works!! to be precise. The dimming works after one or two minutes it got triggered, after it gets triggered everything freezes for a two minutes then then again both on and off works OK without any delays and dimming stops everything for two minutes it looks like a performance issue

Update on this!
I’ve cloned the Tuya app, and added the device above to have more troubleshooting options.

The scenario I am using for reproducing the issue is:
Happy path:

1/ On
2/ Off
Result: No delays

Issue:
1/On
2/ Dim
→ Freeze happens
3/ Off
4/ On

After running this scenario, I am getting below error from the console:

  zigbee-clusters:endpoint ep: 1, cl: time (10), error while handling frame binding_unavailable {
  meta: { dstEndpoint: 1 },
  frame: ZCLStandardHeader {
    frameControl: Bitmap [  ],
    trxSequenceNumber: 174,
    cmdId: 0,
    data: <Buffer 07 00>
  }
} +2m

Do you know what does it mean?

One more thing:
During “freeze” time, when triggering on/off. It is recorded in a console, but not reflected on z Led strip:

zigbee-clusters:cluster ep: 1, cl: onOff (6) received frame defaultResponse onOff.defaultResponse { cmdId: 0, status: 'SUCCESS' } +90ms
2025-08-15T08:36:27.033Z [log] [ManagerDrivers] [Driver:rgb_led_strip_controller] [Device:174731e7-fbc9-4428-8498-d8b99a49decb] changeOnOff() → true
  zigbee-clusters:cluster ep: 1, cl: onOff (6) send frame ZCLStandardHeader {
  frameControl: [ 'clusterSpecific' ],
  data: <Buffer >,
  cmdId: 1,
  trxSequenceNumber: 60
} +1s
  zigbee-clusters:cluster ep: 1, cl: onOff (6) received frame defaultResponse onOff.defaultResponse { cmdId: 1, status: 'SUCCESS' } +81ms
  zigbee-clusters:cluster ep: 1, cl: levelControl (8) read attributes [ 0 ]  +1s
  zigbee-clusters:cluster ep: 1, cl: levelControl (8) send frame ZCLStandardHeader {
  frameControl: [],
  data: levelControl.readAttributes { attributes: [ 0 ] },
  cmdId: 0,
  trxSequenceNumber: 41
} +0ms
  zigbee-clusters:cluster ep: 1, cl: levelControl (8) received frame readAttributesStructured.response levelControl.readAttributesStructured.response {
  attributes: <Buffer 00 00 00 20 24>
} +91ms
  zigbee-clusters:cluster ep: 1, cl: levelControl (8) read attributes result { attributes: <Buffer 00 00 00 20 24> } +2ms
2025-08-15T08:36:31.563Z [log] [ManagerDrivers] [Driver:rgb_led_strip_controller] [Device:174731e7-fbc9-4428-8498-d8b99a49decb] changeOnOff() → false
  zigbee-clusters:cluster ep: 1, cl: onOff (6) send frame ZCLStandardHeader {
  frameControl: [ 'clusterSpecific' ],
  data: <Buffer >,
  cmdId: 0,
  trxSequenceNumber: 61
} +3s

Ok, I was able to gather the logs. This is the full flow

  1. On / off triggered:
2025-08-15T08:40:17.108Z [log] [ManagerDrivers] [Driver:rgb_led_strip_controller] [Device:174731e7-fbc9-4428-8498-d8b99a49decb] changeOnOff() → false   zigbee-clusters:cluster ep: 1, cl: onOff (6) send frame ZCLStandardHeader {   frameControl: [ 'clusterSpecific' ],   data: <Buffer >,   cmdId: 0,   trxSequenceNumber: 67 } +6s   zigbee-clusters:cluster ep: 1, cl: onOff (6) received frame defaultResponse onOff.defaultResponse { cmdId: 0, status: 'SUCCESS' } +95ms
2025-08-15T08:40:23.168Z [log] [ManagerDrivers] [Driver:rgb_led_strip_controller] [Device:174731e7-fbc9-4428-8498-d8b99a49decb] changeOnOff() → true   zigbee-clusters:cluster ep: 1, cl: onOff (6) send frame ZCLStandardHeader {   frameControl: [ 'clusterSpecific' ],   data: <Buffer >,   cmdId: 1,   trxSequenceNumber: 68 } +6s   zigbee-clusters:cluster ep: 1, cl: onOff (6) received frame defaultResponse onOff.defaultResponse { cmdId: 1, status: 'SUCCESS' } +90ms   zigbee-clusters:cluster ep: 1, cl: levelControl (8) read attributes [ 0 ]  +1s   zigbee-clusters:cluster ep: 1, cl: levelControl (8) send frame ZCLStandardHeader {   frameControl: [],   data: levelControl.readAttributes { attributes: [ 0 ] },   cmdId: 0,   trxSequenceNumber: 45 } +0ms   zigbee-clusters:cluster ep: 1, cl: levelControl (8) received frame readAttributesStructured.response levelControl.readAttributesStructured.response {   attributes: <Buffer 00 00 00 20 24> } +102ms   zigbee-clusters:cluster ep: 1, cl: levelControl (8) read attributes result { attributes: <Buffer 00 00 00 20 24> } +1ms

Result: No issues

  1. Dim triggered - freeze
2025-08-15T08:41:18.152Z [log] [ManagerDrivers] [Driver:rgb_led_strip_controller] [Device:174731e7-fbc9-4428-8498-d8b99a49decb] changeDimLevel() → 0.83

  zigbee-clusters:cluster ep: 1, cl: levelControl (8) send frame ZCLStandardHeader {

frameControl: [ 'clusterSpecific' ],

data: levelControl.moveToLevelWithOnOff {

level: 211,

transitionTime: 65535

  },

cmdId: 4,

trxSequenceNumber: 47

} +7s

zigbee-clusters:cluster ep: 1, cl: levelControl (8) received frame defaultResponse levelControl.defaultResponse { cmdId: 4, status: 'SUCCESS' } +78ms

zigbee-clusters:cluster ep: 1, cl: levelControl (8) received frame reportAttributes levelControl.reportAttributes { attributes: <Buffer 00 00 20 d3> } +188ms
  1. Off command - no response on Led
2025-08-15T08:41:42.974Z [log] [ManagerDrivers] [Driver:rgb_led_strip_controller] [Device:174731e7-fbc9-4428-8498-d8b99a49decb] changeOnOff() → false

  zigbee-clusters:cluster ep: 1, cl: onOff (6) send frame ZCLStandardHeader {

frameControl: [ 'clusterSpecific' ],

data: <Buffer >,

cmdId: 0,

trxSequenceNumber: 71

} +7s

zigbee-clusters:cluster ep: 1, cl: onOff (6) received frame defaultResponse onOff.defaultResponse { cmdId: 0, status: 'SUCCESS' } +104ms

zigbee-clusters:cluster ep: 1, cl: onOff (6) received frame reportAttributes onOff.reportAttributes { attributes: <Buffer 00 00 10 00> } +363ms

Interesingly, it reports success in logs..

SUCCESS!

I’ve written my own ZigbeeLightDevice, and everything works ok! What I did is get all the endpoints and apply the changes to all. Surprisingly, it works. I have 1 color led strip so its sufficient for my needs. Here is the code:

'use strict';

const { ZigBeeLightDevice } = require('homey-zigbeedriver');

class rgb_led_strip_controller extends ZigBeeLightDevice {
  async onNodeInit() {
    this._levelEpIds = Object
      .entries(this.zclNode.endpoints || {})
      .filter(([, ep]) => ep?.clusters?.levelControl)
      .map(([id]) => Number(id));

    this.registerCapabilityListener('onoff', (value) => this._setOnOffAll(value));
    this.registerCapabilityListener('dim',   (v) => this._setLevelAll(Math.round(v * 254), 10));
  }

  async _setOnOffAll(on) {
    // Use Move to Level *with On/Off* (cmd 0x04) to force state + level
    const level = on ? 254 : 0;                // 0 = off, >0 = on
    const transitionTime = 0;                  // tenths of a second; 0 = instant
    await Promise.allSettled(this._levelEpIds.map(async (epId) => {
      await this.zclNode.endpoints[epId].clusters.levelControl.moveToLevelWithOnOff({
        level, transitionTime,
      });
    }));
  }

  async _setLevelAll(level, transitionTime = 0) {
    await Promise.allSettled(this._levelEpIds.map(async (epId) => {
      await this.zclNode.endpoints[epId].clusters.levelControl.moveToLevelWithOnOff({
        level, transitionTime,
      });
    }));
  }
}

module.exports = rgb_led_strip_controller;