Control4 SW2-ZX With ZHA

Hello everyone,

I am going away from Control4 since the controller died a few weeks ago. I’m trying to move everything to HA.

Many of our lights were using the Lutron Caseta with their Smart Hubs, and these were a snap to integrate to HA. But I have a few switches that are Control4 C4-SW2-ZX that I’m trying to integrate. I bought recently the SONOFF Zigbee dongle and it was discovered by HA in no time.

I’m now trying to see how I can make the Control4 switches be discovered by ZHA and so far with no success. I’m asking here if anyone found a way to add them to a standard Zigbee controller instead of the C4 controller.

I found this site to help me start rot reset the switches or have them tell me a big about them too.

https://technet.genesis-technologies.ch/control4-zigbee-the-definitive-guide/

Thank you for your help

I believe Control4 use a custom version of Zigbee - if there are only a few switches you can probably save yourself a lot of grief by replacing them. :grin:

I’d start by pairing them to ZHA, turning on debug logging and seeing if you see anything in the logs. If you do, then you could likely build a quirk. But as mentioned above, buying new will be way easier.

So far I was not able to pair any of these switches with ZHA. That’s the reason I’m asking if anyone had more success than I did.

There are a few threads about this - don’t think anyone has managed to do it.

Zigbee Home Automation is built on top of Zigbee Pro. It’s likely that the control 4 switches are Zigbee Pro, but not ZHA and are using a proprietary protocol instead. I had some devices that were similar, based on Zigbee Pro but not ZHA and was able to get them to work, but the amount of modifications I had to make ended up being unsupportable.

If like me, you don’t like being told to just replace them, next steps would be to monitor the logs and see if you see anything in the logs at all during the pair attempt. Quick google search says that control 4 is based on Zigbee Pro, so the question is what do you need to do to get them to join. You could sniff the traffic when they join to the control 4 coordinator with Wireshark and see what you see. They could require a specific network key or perhaps will only join to a specific coordinator. Depending on where the failure is, you may need to modify the coordinator firmware itself.

After many tries, I am removing them one by one. To keep automation possibility, I am installing standard switches with a SONOFF ZBMINIR2 and so far, I can accomplish many things I want to do. With the SONOFF it keeps the replacement at a low investment when I do not require complex settings.

Thank you all for your comments

I don’t see any information of anyone successfully getting Control4 light switches to be controlled through Zigbee from Home Assistant.

I have had some success. Based on the SmartThings drivers written by Patrick Stuart and Ben Schattinger, I managed to get a zigbee quirk which controls a C4-APD120 dimmer switch, and can turn it on and off and adjust the dimmer level. Am I the only one, or am I just not finding the right thread?

I decided to remove everything Control4 and replace them with zig bee or other similar standard devices. I still have a few to remove but I totally abandoned trying to add them to home assistant.

The only thing Control4 I’m keeping is an amplifier that some smart peoples on this forum were able to build an intégration for.

The biggest struggle I had with pairing is that the Control4 devices are annoying persistent in preferring to talk to other Control4 devices. This adds a hop back to the Home Assistant coordinator, and it appears that the insecure Transport Key response fails to pass through that extra hop. This likely is an extra security layer to force the coordinator and device to be close together at the time of an ‘insecure join’. There probably is a setting in Home Assistant to allow the insecure Transport Key response to jump over multiple hops, but I haven’t found it. I can work around it by removing power from all Control4 devices except the one I am attempting to add, but that is a pain.

So far I have the the APD120 (dimmer) and SW120 (switch) turning on and off, and setting dim level for the dimmer. There is some magic I am missing to get the devices to report when the physical button is pressed. The device is supposed to send a request for attributes 0x0008 (access point node id), 0x0009 (access point long id, aka IEEE address), and 0x000A (access point cost). The HA should then respond with its addresses. But I don’t see that message sent.

I think that is the missing piece as to why the physical button presses aren’t being reported, but I can’t figure out how to trigger the Control4 to send that request. Without the buttons being reported, the scene controller is useless, and the light switches are useable, but get out of sync often. There is a polling loop to bring the back into sync, but that is quite slow.

I did get the LOZ-5S1-W dual switched outlet working too.

I also figured out the magic to get the devices to send button click messages to Home Assistant. Needed to send a Report Attributes to the device profile 0xC25D, endpoint 2, cluster 0x0001, with attribute 8 = coordinator short address (0x0000), attribute 9 = coordinator ieee address, attribute 0x0a = 0x02, and then send an MTORR.

So now I have the 7-button scene controllers (C4-KC120277) working too. Those were a real pain because Control4 doesn’t report model numbers using the Zigbee standard, and the quirk signatures for both C4-KC120277 and C4-APD120 are identical. Had to do some magic to capture and cache the model number from the devices’ broadcast Report Attributes messages which do contain the model number.

I seem to just be talking to myself, but if there is anyone interested, I’ve uploaded my current state of the quirks to zha-device-handlers/zhaquirks/control4 at control4 · pvanbaren/zha-device-handlers · GitHub

I have the following devices working in Home Assistant:

  • C4-APD120 (dimmer)
  • C4-4SF120 (fan)
  • C4-SW120277 (switch)
  • loz-5s1-w (dual switched outlet)
  • C4-KC120277 (scene controller)
  • C4-Z2IO-ZP (garage door relay module)

I see you answer, but I really gave up on anything Control4, except the multi-room amp where some smart folks on this forum created a great integration that works pretty well. But most switches named control4 have been remove now.

I can look at what I have and see if anything fits what you successfully integrated and, maybe, give them a chance. But I'm not sure if I have similar switches.

I also moved to Zigbee2MQTT, so I'm not sure how that translate from ZHA. The problem I had was to get the switches to show into HA at all. I tried to integrate a door sensor, and sometimes I was able to see it in HA, but not to a degree I could do anything with it. I replaced it by an IKEA device that is working just fine.

Doing a Google search, Gemini told me this:

ZHA vs. Zigbee2MQTT "Quirks"

  • ZHA (custom_quirks_path): Uses Python scripts (.py) to handle deviations from the ZCL specification.
  • Zigbee2MQTT (external_converters): Uses JavaScript converter files (.js) to parse incoming messages and expose entities.

There is probably a little work to do before it could work with Z2MQTT

I pushed up my current state. I also was able to get the SR260 remotes working, and added some scripts and blueprints to work with the devices (e.g. set LEDs on the scene controllers/switches, map actions to the SR260 remote buttons, display menu on the SR260 remote, with actions for the menu selection). Things have been working pretty consistently for me.

I don't use Zigbee2MQTT, so I can't say what it would take to port it over. I did document the protocols in the 'documentation' folder. The main trick is the Control4 devices do not identify themselves in a standard Zigbee way, so you need special logic get them initialized.

If anyone is interested I was able to integrate C4-KP6-Z via Zigbee2Mqtt converter AND custom code.
Code required to intercept/publish APS frames that do not contain ZCL, but C4 propietary protocol instead.

PoC: https://www.youtube.com/watch?v=eDS3Qqf_STI

Link to converter and diffs:

Unfortunately it would not go to Zigbee2Mqtt upstream, as the author decided not to do "invasive" changes to support propietary C4 stuff. But yes, it works great.

(should work with any Zigbee keypads that are based on the same C4 "ascii" protocol)

@pvanbaren — thank you for these quirks. I had five Control4 dimmers that were inert wall decorations after the controller went away, and they’re now paired, routing, and controllable from Home Assistant. Genuinely appreciated.

While getting there I hit two bugs that I think stop every Control4 quirk from loading on current zha-quirks, plus a model that isn’t covered yet. Patched files and a unified diff against your control4 branch are here:

Issues are disabled on your repo (fork default) so I’m posting here — happy to open a PR instead if you’d prefer.


1. ImportError: cannot import name 'BUTTON_7' — blocks everything

c4_helpers.py imports BUTTON_7 and BUTTON_8 from zhaquirks.const, which only defines BUTTON_1..BUTTON_6. Reproduced in a clean venv with zha-quirks 0.0.112 / zigpy 0.84.0:

ImportError: cannot import name 'BUTTON_7' from 'zhaquirks.const'

Because the chain is c4_helpers → c4_hooks → every device module, that one line prevents all the Control4 quirks from loading. It fails silently from the user’s side — devices pair fine but come up generic with quirk_applied: false. A defensive import fixes it:

python

try:
    from zhaquirks.const import BUTTON_7, BUTTON_8
except ImportError:
    BUTTON_7 = "button_7"
    BUTTON_8 = "button_8"

2. Most device modules are never imported

The guaranteed-import block at the bottom of c4_hooks.py only imports control4_fan and control4_z2io_zp. control4_dimmer, control4_switch, control4_scene_controller and control4_outlet rely on ZHA’s directory scan, which doesn’t reach into custom_zha_quirks/control4/ — so their _C4_MODEL_QUIRK_MAP[...] registration never runs and model dispatch finds nothing. Adding the other four imports alongside the existing two fixes it.

3. LSZ-101 / LDZ-101 dimmers

Same protocol as the APD120, different signature: manufacturer code 0xABCD rather than 0x1040, the full standard cluster set on ep 1 (0000,0003,0004,0005,0006,0008,000a), and an extra ep 198 (profile 0xC25E, devtype 0x0101). Since get_device dispatches on model string, registering aliases against your existing dimmer class appears to be enough:

python

for _alias in ("LSZ-101", "LSZ-102", "LDZ-101", "LDZ-102"):
    _C4_MODEL_QUIRK_MAP[_alias] = Control4APD120Dimmer

Full signature JSON is in the repo README.


Where I’m still stuck. With all three applied on my live system the dimmers still report quirk_applied: false and model: unk_model, and my registration log line never appears — so something else is preventing c4_hooks from loading there that I can’t see without deeper log access. Two data points that might help:

  • /config/.storage/c4_quirk_data.json correctly holds all five of my devices (4x LSZ-101, 1x LDZ-101), yet ZHA still shows unk_model after a restart, so the cached model isn’t reaching get_device.
  • The hooks were definitely live at one point — right after pairing I saw C4 intercept: handle_message failed on ep 197: 'NoneType' object has no attribute 'command_id'.

What works regardless. All five dimmers pair reliably, act as Zigbee routers (which incidentally rescued several stranded battery sensors on my mesh), and respond correctly to on/off/brightness through the generic light entity. Every service call raises Failed to send request: device did not respond because Control4 never sends the expected ACK, but the device executes the command. No state feedback, as expected without the quirk.

My motivation for chasing the quirk is C4LEDCluster — I’d like to drive the LED bars from light state (red when off, green when on).

One doc suggestion. The reset sequence is orientation-sensitive and Control4 dimmers are often installed upside down. All five of mine are, and the documented 13x top, 4x bottom, 13x top did nothing until I mirrored it to 13x bottom, 4x top, 13x bottom. Easy tell: if pressing the upper half of the paddle turns the light off, it’s inverted. That cost me a lot of attempts, and a line in the README would save the next person the same.

Your other two notes were spot on and worth promoting to the README as well: the coordinator has to be close during pairing, and an already-joined Control4 device will relay for a new one and break the handshake — pair one at a time.

Environment: HA 2026.7, ZHA, Home Assistant Connect ZBT-1, no Control4 controller. Happy to run diagnostics, capture traffic, or test patches — the devices are installed and I can re-pair them freely.

Thank you defjam903 and pvanbaren for these quirks. They saved my life after my controller stopped working.

I managed to join the following to the Zigbee network:

3 x LDZ-101 (In-wall dimmer)
1 x LSZ-101 (In-wall switch)
4 x LOZ-5D1-W (dual dimmer outlet)
2 x LOZ-5S1-W (dual switched outlet)
1 x KPZ-6B1 (6-button keypad)

To add the dual dimmer outlets, I needed to add the following code to the control4_outlet.py file:

for _c4_alias in (
    "LOZ-5D1-W", "C4-LOZ-5D1-W",
):
    _C4_MODEL_QUIRK_MAP[_c4_alias] = Control4LOZ5S1WOutlet
_LOGGER.warning("C4 LOZ-5S1-W: registered aliases")

Additionally, I encountered the following issues:

  • None of the devices have a button click event.
  • The dual dimmer outlets shows up and function as switches;
  • The in-wall switch shows up as a dimmer.

Furthermore, when I try to change the keypad LED color, I get the following error:

Failed to execute action script/control4_set_led_color. Cluster 64579 not found on endpoint 3 while issuing command 0 with args None

Is it possible to fix this issues? I’m new to Home Assistant and Python, but I’d be happy to try to contribute.

I am running Home Assistant OS core-2026.9.1 on a computer with a SONOFF ZBDongle-E.

Update — a lot of progress since my last post!

Since I posted the issues above, I’ve spent a good amount of time digging into these quirks and fixing them one by one. Wanted to share the results in case they help anyone else running Control4 Zigbee devices on ZHA.

The three issues from my earlier post are all fixed:

  • Button click events — the paddle/button presses on dimmers and switches now show up as proper HA Event entities (press, click, double/triple/quadruple click, hold, and release) instead of doing nothing.
  • LOZ-5D1-W showing as a switch instead of a dimmer — both outlets now do real graduated dimming, including dragging the brightness slider live while the light is on, and correctly restore their previous brightness on a plain on/off toggle.
  • LSZ-101 showing as a dimmer instead of a switch — it’s now registered separately and shows up as a plain switch, the way it should.

The LED color error ("Cluster 64579 not found… ") turned out to be because that script targets the scene controller’s LED protocol, which isn’t what the dimmer or the keypad actually speak on the wire. Both devices now have their own dedicated LED handling instead:

  • The dimmer/outlet family got two new hardware-config switches (button_attached/led_attached) plus 4 per-button RGB light entities (top/bottom, on and off color).
  • A brand-new quirk was built from scratch for the KPZ-6B1 6-button keypad — it wasn’t supported at all before. It now exposes 6 press/release sensors and 6 per-button RGB lights, plus two bulk “set all LEDs” commands so you don’t have to script six separate calls. Along the way I hit (and fixed) a fun bug where the keypad’s LED would flash and revert to a stale color every time you physically pressed the button — turned out our quirk was accidentally putting the device into the wrong internal mode (“Keypad Managed” doesn’t mean what it sounds like — I had to pull the actual compiled Control4 driver off a spare controller to figure that one out).

Everything is documented in the repo now, including full protocol write-ups for each device and the HA scripts for LED control:

:link: zha-device-handlers/zhaquirks/control4 at control4 · wmariz/zha-device-handlers · GitHub

Same disclaimer as always — this is all reverse-engineered from packet captures and logs, not official Control4 documentation, so use at your own risk. But at this point I’ve got dimmers, switches, dimming outlets, switched outlets and the keypad all running reliably on real hardware with no Control4 controller in the loop.