- Notifications
You must be signed in to change notification settings - Fork7.8k
How to integrate multiple gang switches with ESP32-C6 Arduino Zigbee_On_Off_Switch?#11089
-
BoardESP32-C6 Device DescriptionDev module Hardware ConfigurationBase setting Versionv3.1.0 IDE NameArduino IDE 2.3.4 Operating SystemWindows11 Flash frequency80Mhz PSRAM enabledno Upload speed115200 DescriptionHello, I successfully integrated the wall light switches from Tuya and other manufacturers, and the switch On/Off works fine. However, the wall light switch I have is a 3-gang switch. I am new to Zigbee and am having difficulty understanding how to set it up. Sketch#ifndef ZIGBEE_MODE_ZCZR#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"#endif#include"Zigbee.h"/* Zigbee switch configuration*/#defineSWITCH_ENDPOINT_NUMBER5uint8_t buttonPin = BOOT_PIN;ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER);int buttonState;int lastButtonState = LOW;unsignedlong lastDebounceTime =0;// the last time the output pin was toggledunsignedlong debounceDelay =50;// the debounce time; increase if the output flickers/********************* Arduino functions **************************/voidsetup() { Serial.begin(115200);//Init button switchpinMode(buttonPin, INPUT_PULLUP);//Optional: set Zigbee device name and model zbSwitch.setManufacturerAndModel("SPACETALK","ZigbeeWALLSwitch");//Optional to allow multiple light to bind to the switch zbSwitch.allowMultipleBinding(false);//Add endpoint to Zigbee Core Serial.println("Adding ZigbeeSwitch endpoint to Zigbee Core"); Zigbee.addEndpoint(&zbSwitch);//Open network for 180 seconds after boot Zigbee.setRebootOpenNetwork(180);// When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR modeif (!Zigbee.begin(ZIGBEE_COORDINATOR)) { Serial.println("Zigbee failed to start!"); Serial.println("Rebooting..."); ESP.restart(); } Serial.println("Waiting for Light to bound to the switch");//Wait for switch to bound to a light:while (!zbSwitch.bound()) { Serial.printf(".");delay(500); } Serial.println();// Optional: List all bound devices and read manufacturer and model name std::list<zb_device_params_t *> boundLights = zbSwitch.getBoundDevices();for (constauto &device : boundLights) { Serial.printf("Device on endpoint %d, short address: 0x%x\r\n", device->endpoint, device->short_addr); Serial.printf("IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0] );char *manufacturer = zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr);char *model = zbSwitch.readModel(device->endpoint, device->short_addr, device->ieee_addr);if (manufacturer !=nullptr) { Serial.printf("Light manufacturer: %s\r\n", manufacturer); }if (model !=nullptr) { Serial.printf("Light model: %s\r\n", model); } } Serial.println(" ---- END SETUP ----"); }voidloop() {int reading =digitalRead(buttonPin);if (reading != lastButtonState) {// reset the debouncing timer lastDebounceTime =millis(); }if ((millis() - lastDebounceTime) > debounceDelay) {if (reading != buttonState) { buttonState = reading;// only toggle the LED if the new button state is HIGHif (buttonState == HIGH) {// Toggle light Serial.println(" --> BTN Input : Light Toggle"); zbSwitch.lightToggle(); } } } lastButtonState = reading;if (Serial.available()) { String command = Serial.readStringUntil('\n'); Serial.print(" SIG IN :"); Serial.println(command);if (command =="on") { Serial.println(" --> SIG Input : Light ON"); zbSwitch.lightOn(); }elseif (command =="off") { Serial.println(" --> SIG Input : Light OFF"); zbSwitch.lightOff(); }elseif (command =="freset") { Serial.println(" --> SIG Input : Factory Reset!");delay(1500); Zigbee.factoryReset(); } }staticuint32_t last_print =0;if (millis() - last_print >30000) { last_print =millis(); zbSwitch.printBoundDevices(Serial); }} Debug MessageOther Steps to ReproduceNo response I have checked existing issues, online documentation and the Troubleshooting Guide
|
BetaWas this translation helpful?Give feedback.
All reactions
Replies: 12 comments
-
Hi@luxert, I have been playing with this today and for now without any changes needed to the Zigbee library you can use approach of single Switch endpoint (Coordinator) + multiple light connected to it (end devices). You just need to set the zbSwitch.allowMultipleBinding to true. After that all the lights can connect and will be bound to the switch. Use any of the control function voidlightToggle(); To control lights individually, you need to specify the voidlightToggle(uint8_t endpoint,uint16_t short_addr);voidlightToggle(uint8_t endpoint,esp_zb_ieee_addr_t ieee_addr); You can get the endpoints and addresses from the list of bound devices, which you can get by calling Let me know if you need any help. I have also in progress the 2nd approach of having multiple Switch endpoints where each switch endpoint can have 1 light bounded. This approach needs changes in the Zigbee library and is in progress. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Thank you very much for the detailed answer.@P-R-O-C-H-Y I registered two wall light switches using zbSwitch.allowMultipleBinding(true) and successfully controlled the switches individually through the endpoint and Short_addr. I have a few more questions: After registering the device, the Short_Addr is displayed correctly in getBoundDevices(). However, after rebooting the ESP32-C6, the Short_Addr is displayed as 0x0. While the display shows 0x0, I can still control the device individually with the previously recorded short_addr. (When a signal is sent, the response shows the correct Short_addr). Is this a bug? `----Register First 09:44:07.121 -> Device on endpoint 1, short address: 0x9a5f ----After Reboot 09:48:21.556 -> Device on endpoint 1, short address: 0x0 I connected two wall light switches for testing. Can I unpair only one of the connected devices using its Short_addr and IEEE addr, etc.? In other words, can I unpair a specific device using Short_addr, etc.? Currently, I am performing a factory reset to unpair all devices and then registering them individually again. Can I check the state of the wall light switch? I can use LightOn() and LightOff() to turn the switches on and off. However, I would like to know the state when the user turns the wall light switch on or off manually. I believe the off-the-shelf product might provide a response, but nothing is reported in the handler. I’m wondering if there is a way to know the state, either via an event or polling. Can I check the connection status of the wall light switch? I turned off the power of one of the two connected wall light switches. When calling LightOn(), the following happens:
The switch that is still on works normally and the response appears, while the switch that is off shows the NLME Status. I’m wondering if I can detect the device's connection status (e.g., Connected, Joined, or Disconnected) or any state without sending a control signal. Do you have an estimate of when support for Tuya-style 3Gang wall light switches, such as Top_Button, Center_Button, and Bottom_Button, will be available? Can the current control state not be feedback in the Zigbee_On_Off_Switch.ino through the zb_cmd_default_resp_handler()? Once again, I am very, very, very grateful for your help! |
BetaWas this translation helpful?Give feedback.
All reactions
-
You are welcome, I am glad that worked well for you@luxert.
Thing is that only the ieee address + endpoint is stored in the binding table, which is recalled when you reset(reboot) the device. The devices still have the same short addresses, so you can use that to control it. It's not bug tho.
Currently no, but I will take a look and add API to do this. It should be possible for sure. Good feature request there.
I was not testing that, as I most of time use HomeAssistant which does this exact thing. I will take a look on the correct approach.
Not sure, as the device did not leave the network, it's just offline. I can take a look on this also.
Can you please provide more info about this? I was assuming you are now doing exactly this, so there is not much needed to add some kind of support for this.
I will take a look :) |
BetaWas this translation helpful?Give feedback.
All reactions
-
Question 5. Test.. For Tuya-style multi-gang light switches, I tested by changing the Endpoint to 1, 2, and 3 using zbSwitch.lightOn(Endpoint, Short_addr), and both the second and third buttons worked properly. if (command=="on11") {Serial.println(" --> SIG Input : Light ON");zbSwitch.lightOn(1,0x59d1); }elseif (command=="on12") {Serial.println(" --> SIG Input : Light ON");zbSwitch.lightOn(2,0x59d1); } |
BetaWas this translation helpful?Give feedback.
All reactions
🎉 1
-
@P-R-O-C-H-Y |
BetaWas this translation helpful?Give feedback.
All reactions
-
@luxert Do you mean to receive a response that the command did the effect (turned on/off), ro you mean if you physically turn on/off the switch so it sends a report to coordinator that it have been switched? |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
@P-R-O-C-H-Y |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
@P-R-O-C-H-Y and added code to the bindCb() function of ZigbeeSwitch.cpp for state change reporting. However, I am receiving the response voidZigbeeSwitch::bindCb(esp_zb_zdp_status_tzdo_status,void*user_ctx) {if (zdo_status==ESP_ZB_ZDP_STATUS_SUCCESS) {log_i(" -------->>> Bound successfully!");if (user_ctx) {zb_device_params_t*light= (zb_device_params_t*)user_ctx;log_i("The light originating from address(0x%x) on endpoint(%d)",light->short_addr,light->endpoint);_instance->_bound_devices.push_back(light);esp_zb_zcl_config_report_cmd_treport_cmd= {0};boolreport_change=1;report_cmd.zcl_basic_cmd.dst_addr_u.addr_short=light->short_addr;// Tuya Multi Gang switch addrreport_cmd.zcl_basic_cmd.dst_endpoint=light->endpoint;// Tuya Multi Gang switch endpointreport_cmd.zcl_basic_cmd.src_endpoint=5;// ESP32-c6 Switch Endpointreport_cmd.address_mode=ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;report_cmd.clusterID=ESP_ZB_ZCL_CLUSTER_ID_ON_OFF;esp_zb_zcl_config_report_record_trecords[]= { {//.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV, .direction=ESP_ZB_ZCL_REPORT_DIRECTION_SEND, .attributeID=ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, .attrType=ESP_ZB_ZCL_ATTR_TYPE_BOOL, .min_interval=0, .max_interval=30, .reportable_change=&report_change }, };report_cmd.record_number=sizeof(records) /sizeof(esp_zb_zcl_config_report_record_t);report_cmd.record_field=records;esp_zb_zcl_config_report_cmd_req(&report_cmd);log_i(" -------->>> REPORT CONFIG SEND !!!! <<<--------"); }_is_bound= true; }} |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
@P-R-O-C-H-Y The next issue is how to specify and unbind a bound device (and also delete the bind table). For example, when two devices are connected and I want to disconnect the first device, I used the IEEE address of the first device as shown below, voidSTZigbeeSwitch::remove_device(esp_zb_ieee_addr_tieee_address) {esp_zb_zdo_mgmt_leave_req_param_tleave_req;//leave_req.device_address = ieee_address,memcpy(leave_req.device_address,ieee_address,sizeof(esp_zb_ieee_addr_t));leave_req.remove_children= true;leave_req.rejoin= false;Serial.printf(" >> LEAVE REQUEST IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n",leave_req.device_address[0],leave_req.device_address[1],leave_req.device_address[2],leave_req.device_address[3],leave_req.device_address[4],leave_req.device_address[5],leave_req.device_address[6],leave_req.device_address[7] );esp_zb_zdo_device_leave_req(&leave_req,leave_cb,NULL);} but it failed. I am also wondering if I should use I am wondering if there is a solution for this. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Hello. I successfully unbound the device from the network using voidZigbeeSwitch::zigbeeDeviceUnbindReq(uint16_trid,esp_zb_ieee_addr_tsrc_addr,esp_zb_ieee_addr_tdes_addr,uint16_tcluster_id,uint8_tsrc_ep,uint8_tdes_ep){ESP_LOGE("ZIGBEE","Sending UNBIND");esp_zb_zdo_bind_req_param_tbind_req;uint16_t*user_rid= (uint16_t*)malloc(sizeof(uint16_t));*user_rid=rid;bind_req.cluster_id=cluster_id;bind_req.dst_addr_mode=ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;memcpy(bind_req.src_address,src_addr,sizeof(esp_zb_ieee_addr_t));memcpy(bind_req.dst_address_u.addr_long,des_addr,sizeof(esp_zb_ieee_addr_t));//bind_req.dst_endp=des_ep;//bind_req.src_endp=src_ep;bind_req.dst_endp=1;bind_req.src_endp=5;bind_req.req_dst_addr=esp_zb_address_short_by_ieee(src_addr);esp_zb_zdo_device_unbind_req(&bind_req,unbindnew_cb, (void*)user_rid);}voidZigbeeSwitch::unbindnew_cb(esp_zb_zdp_status_tzdo_status,void*user_ctx){ESP_LOGE("ZIGBEE","CALLBACK UNBIND status %d",zdo_status);free(user_ctx);} I referred to the post on the following link:espressif/esp-zigbee-sdk#318 Thanks!!!@P-R-O-C-H-Y |
BetaWas this translation helpful?Give feedback.
All reactions
🚀 1
-
Hi@luxert, I am glad you made that work! Great job. About the "automatically receive the light's status report", I think it may be done using the POLL cluster, but this is not implemented yet. I may need to take a look and prepare the code. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Hello all, great work |
BetaWas this translation helpful?Give feedback.
All reactions
This discussion was converted from issue #10867 on March 12, 2025 18:07.