Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

ESP32-C6 zigbee dimmable light with range extender (router) function #11028

MikaFromTheRoof started this conversation in Question - Community Help
Discussion options

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);
}
You must be logged in to vote

Replies: 3 comments 4 replies

Comment options

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

image

You must be logged in to vote
3 replies
Comment options

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.

Comment options

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.

Comment options

I will try that. Thank you for responding and your great work here!!

Comment options

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

You must be logged in to vote
0 replies
Comment options

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.

You must be logged in to vote
1 reply
Comment options

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.

devxjx.js

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /