-
Notifications
You must be signed in to change notification settings - Fork 7.7k
ESP32-C6 zigbee dimmable light with range extender (router) function #11028
-
Hey everyone,
I tried to create a zigbee device with my DFRobot Beetle ESP32-C6 board, that features two endpoints: one for a dimmable light function and one for the range extender (router) function. I am using version 3.2.0-RC1 (I believe 3.1.3 doesn't have router functionality, right?)
You can find my code below. It's mostly these two examples combined: Zigbee_Dimmable_Light and Zigbee_Range_Extender. I use the ESP32 PWM dimming, because it has a higher resolution, thus it was easier to do some gamma correction (brightness changes look more linear to the human eye).
I uploaded the code to my board and then added it to my Home Assistant via Zigbee2MQTT. When I do this with the device featuring only one zigbee endpoint, it always works just fine. But when my device uses both zigbee endpoints (light and router) it sometimes works and sometimes not. Not working means, that I can add it to Zigbee2MQTT, but it wont react to any commands like switching the LED on or off.
I am quite new to ESP32 with Zigbee so I would like to ask you more experienced folks, if you might have an idea, why my device isn't working properly with two zigbee endpoints. Did I do it right in my code with combining the two endpoints or should I change something? Might the problem be located somewhere else? Maybe Zigbee2MQTT can't handle those selfmade zigbee devices correctly?
Thanks for your help!!
Here comes the code:
#ifndef ZIGBEE_MODE_ZCZR #error "Zigbee coordinator/router mode is not selected in Tools->Zigbee mode" #endif #include "Zigbee.h" // Zigbee dimmable light and range extender configuration #define USE_CUSTOM_ZIGBEE_CONFIG 1 //if custom configuration (1) or default (0) should be used for the range extender #define ZIGBEE_EXTENDER_ENDPOINT 1 #define ZIGBEE_LIGHT_ENDPOINT 10 uint8_t led = 23; uint8_t button = BOOT_PIN; // ESP32 PWM dimming settings const int PWM_FREQ = 500; const int PWM_RESOLUTION = 16; // variables for dimming int maxLevelTransformed = pow(2, PWM_RESOLUTION)-1; // internal max brightness level int levelTransformed; // zigbee brightness value that got transformed into internal brightness level int lastLevelTransformed; // internal brightness level of last brightness change // create endpoints ZigbeeDimmableLight zbDimmableLight = ZigbeeDimmableLight(ZIGBEE_LIGHT_ENDPOINT); ZigbeeRangeExtender zbExtender = ZigbeeRangeExtender(ZIGBEE_EXTENDER_ENDPOINT); /********************* LED functions **************************/ void setLight(bool state, uint8_t level) { // transform zigbee brightness level (0-254) to internal level levelTransformed = transformBrightness(level); // ignore brightness changes between two equal values if(levelTransformed == lastLevelTransformed) return; // change brightness if (!state) { ledcFade(led, lastLevelTransformed, 0, 100); // smooth zigbee brightness changes happen every 100 ms return; } ledcFade(led, lastLevelTransformed, levelTransformed, 100); // smooth zigbee brightness changes happen every 100 ms // log brightness changes Serial.print("[Brightness] Zigbee: "); Serial.print(level); Serial.print(" | Internal before: "); Serial.print(lastLevelTransformed); Serial.print(" | Internal target: "); Serial.print(levelTransformed); Serial.print(" / "); Serial.println(maxLevelTransformed); // remember internal level for next brightness change for smooth zigbee brightness changes lastLevelTransformed = levelTransformed; } // identify function - 100% example code void identify(uint16_t time) { static uint8_t blink = 1; log_d("Identify called for %d seconds", time); if (time == 0) { // If identify time is 0, stop blinking and restore light as it was used for identify zbDimmableLight.restoreLight(); return; } ledcWrite(led, maxLevelTransformed * blink); blink = !blink; } // function to transform zigbee brightness values (0-254) to the values fitting the PWM_RESOLUTION with gamma correction int transformBrightness(int value) { float gamma = 2.2; return (int) (pow(value / 254.0, gamma) * maxLevelTransformed); } /********************* Arduino functions **************************/ void setup() { Serial.begin(115200); Serial.println(); Serial.println(); // Init LED and turn it off ledcAttach(led, PWM_FREQ, PWM_RESOLUTION); ledcWrite(led, 0); // Init button for factory reset pinMode(button, INPUT_PULLUP); // Set Zigbee device name and model zbDimmableLight.setManufacturerAndModel("MyHardware", "ZigbeeDimmer"); zbExtender.setManufacturerAndModel("MyHardware", "ZigbeeDimmer"); // Optional: Set callback function for device identify zbDimmableLight.onIdentify(identify); zbExtender.onIdentify(identify); // Set power source zbDimmableLight.setPowerSource(ZB_POWER_SOURCE_MAINS); zbExtender.setPowerSource(ZB_POWER_SOURCE_MAINS); // Set callback function for light change zbDimmableLight.onLightChange(setLight); // Add endpoints to Zigbee Core Serial.println("Adding ZigbeeRangeExtender endpoint to Zigbee Core"); Zigbee.addEndpoint(&zbExtender); Serial.println("Adding ZigbeeLight endpoint to Zigbee Core"); Zigbee.addEndpoint(&zbDimmableLight); // start Zigbee in Router mode with custom or default configuration #if USE_CUSTOM_ZIGBEE_CONFIG // custom Zigbee configuration for Zigbee Extender esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ROUTER_CONFIG(); zigbeeConfig.nwk_cfg.zczr_cfg.max_children = 20; // 10 is default // When all EPs are registered, start Zigbee with custom config if (!Zigbee.begin(&zigbeeConfig)) { #else // use default Zigbee configuration for Zigbee Extender // When all EPs are registered, start Zigbee as ROUTER device if (!Zigbee.begin(ZIGBEE_ROUTER)) { #endif Serial.println("Zigbee failed to start!"); Serial.println("Rebooting..."); ESP.restart(); } // wait for connection an blink LED until connection established Serial.println("Connecting to network"); bool ledOn; while (!Zigbee.connected()) { Serial.print("."); if (ledOn) { ledcWrite(led, 0); } else { ledcWrite(led, (int) (maxLevelTransformed * 0.1)); } ledOn = !ledOn; delay(500); } Serial.println(); Serial.println("Connected"); Serial.println(); ledcWrite(led, 0); } void loop() { // Checking button for factory reset if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling delay(100); int startTime = millis(); while (digitalRead(button) == LOW) { delay(50); if ((millis() - startTime) > 3000) { // If key pressed for more than 3secs, factory reset Zigbee and reboot Serial.println("Resetting Zigbee to factory and rebooting in 1s."); delay(1000); Zigbee.factoryReset(); } } // Increase blightness by 50 every time the button is pressed zbDimmableLight.setLight(true, zbDimmableLight.getLightLevel() + 50); } delay(100); }
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 3 comments 4 replies
-
Hi @hansfriedringelpuetz, the "rangeExtender" endpoint is there mostly for uses cases, where no other endpoint is needed (wanted).
You can remove the rangeExtender endpoint and use just the light endpoint. The Zigbee must be set to ROUTER mode in begin.
Zigbee.begin(ZIGBEE_ROUTER) or with the custom config like example shows.
You have 3 roles which can be used and start Zigbee with:
ZIGBEE_END_DEVICE (default, when Zigbee.begin() is empty) -> end device
ZIGBEE_ROUTER -> creating router between coordinator and end devices (extending the range for coordinator)
ZIGBEE_COORDINATOR -> forming and controlling the network, only 1 can exist
Beta Was this translation helpful? Give feedback.
All reactions
-
great, thank you for the clarification! I think I got the terms router and range extender confused...
It's now working great! There is just one more thing I would like to ask you about:
If I configure my device to run as an end device, Zigbee2MQTT shows it in the map view with lots of connections with 0 link quality:
grafik
do you know why this might be the case? All other end devices are displayed with only one connection.
Beta Was this translation helpful? Give feedback.
All reactions
-
I am sorry I don't use the Zigbee2MQTT, I am using the ZHA in HomeAssistant. Maybe you can ask this on our discord channel in Zigbee-support group. There are probably some guys using the Z2M.
Beta Was this translation helpful? Give feedback.
All reactions
-
I will try that. Thank you for responding and your great work here!!
Beta Was this translation helpful? Give feedback.
All reactions
-
i am new on zigbee,i have esp32-c6 wroom-1,i used range-extender but zigbee2mqtt only recognize end device,somebody can help to me how to extend my zigbee network with esp32-c6,thanks
image
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi, I’m trying the same thing — to get the device recognized as a Router instead of an EndDevice (using the HA_color_dimmable_light example).
What worked for me was running a Reinterview — it seems Z2M had remembered my previous attempts using same device just as light. After the reinterview completed and I reloaded the page, the device was indeed shown as a Router (blue).
However, it’s still marked as unsupported. I also tried adding a custom converter.js, but unfortunately that didn’t resolve the issue.
Beta Was this translation helpful? Give feedback.
All reactions
-
By adding my own device definition (devxjx.js) into the directory
..\zigbee2mqtt\external_converters\ (note: this folder doesn’t exist by default, it must be created), and restarting Zigbee2MQTT, the device is now recognized as supported.
Note that the way of handling custom device definitions has changed since Zigbee2MQTT 2.x. In earlier versions, the location of external converters was specified directly in configuration.yaml. From 2.x onwards, you now place your custom .js files in the external_converters directory.
I also updated the manufacturer and model identifiers before compilation in
.\esp-zigbee-sdk\examples\esp_zigbee_HA_sample\HA_color_dimmable_light\main\esp_zb_light.h:
...
/* Basic manufacturer information */
#define ESP_MANUFACTURER_NAME "\x03""XJX" /* Customized manufacturer name */
#define ESP_MODEL_IDENTIFIER "\x08""H2Router" /* Customized model identifier */
...
Note: the numbers before each text constant specify the length of the string.
Beta Was this translation helpful? Give feedback.