unable to add my 4 gang zigbee switch to tuya smart app using wireless tuya zigbee gateway

Let's chat here.


Post Reply
137013701991
Posts: 1

I'm using the ESP32-C6 Zigbee stack to implement a Tuya-based multi-gang wall switch.
The 1-, 2-, and 3-gang versions work correctly and are identified properly.
However, the 4-gang version is detected as a single-gang device by common Zigbee coordinators (Smart Gateway molel : JMWZG1).
Its functionality is also incorrect, as only one endpoint/cluster appears to be exposed.
It seems the stack is not advertising or handling the correct endpoints/clusters for the 4-gang variant.

Additionally, the device model reported by the stack appears as Chinese characters in the app instead of the correct model name.

Image

#include "esp_check.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_timer.h"

#include "esp_zigbee_core.h"
#include "esp_zigbee_type.h"
#include "esp_zigbee_cluster.h"
#include "esp_zigbee_endpoint.h"

// ZCL
#include "zcl/esp_zigbee_zcl_basic.h"
#include "zcl/esp_zigbee_zcl_identify.h"
#include "zcl/esp_zigbee_zcl_on_off.h"

#include <string.h>

static QueueHandle_t button_queue = NULL;

#define TAG "ZB_SWITCH"

/* Zigbee configuration /
#define INSTALLCODE_POLICY_ENABLE false
#define ESP_ZB_PRIMARY_CHANNEL_MASK (1l << 15)
#define ALL_ZIGBEE_CHANNELS
((1 << 11) | (1 << 12) | (1 << 13) | (1 << 14) |
(1 << 15) | (1 << 16) | (1 << 17) | (1 << 18) |
(1 << 19) | (1 << 20) | (1 << 21) | (1 << 22) |
(1 << 23) | (1 << 24) | (1 << 25) | (1 << 26))
/ Basic manufacturer information */
#define ESP_MANUFACTURER_NAME "\x09""ESPRESSIF"
#define ESP_MODEL_IDENTIFIER "\x07"CONFIG_IDF_TARGET

/* ---- ZED Configuration ---- */
#define ESP_ZB_ZED_CONFIG()
{
.esp_zb_role = ESP_ZB_DEVICE_TYPE_ED,
.install_code_policy = INSTALLCODE_POLICY_ENABLE,
.nwk_cfg.zed_cfg = {
.ed_timeout = 10,
.keep_alive = 300000 },
}

#define ESP_ZB_DEFAULT_RADIO_CONFIG()
{
.radio_mode = ZB_RADIO_MODE_NATIVE,
}

#define ESP_ZB_DEFAULT_HOST_CONFIG()
{
.host_connection_mode = ZB_HOST_CONNECTION_MODE_NONE,
}

// *********** relay ***********
#define RELAY1_GPIO GPIO_NUM_2
#define RELAY2_GPIO GPIO_NUM_15
#define RELAY3_GPIO GPIO_NUM_11
#define RELAY4_GPIO GPIO_NUM_8

#define BUTTON1_GPIO GPIO_NUM_3
#define BUTTON2_GPIO GPIO_NUM_9
#define BUTTON3_GPIO GPIO_NUM_10
#define BUTTON4_GPIO GPIO_NUM_12
// *********** Endpoint **************
#define EP_SWITCH1 1
#define EP_SWITCH2 2
#define EP_SWITCH3 3
#define EP_SWITCH4 4

static bool relay_state[4] = {false, false, false, false};
static volatile bool button_flag[4] = {false, false, false, false};

static void send_onoff_report(uint8_t ep, bool state)
{
uint8_t val = state ? 1 : 0;

// update Attribute
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_set_attribute_val(
ep,
ESP_ZB_ZCL_CLUSTER_ID_ON_OFF,
ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
&val,
false
);
esp_zb_lock_release();

// Report
esp_zb_zcl_report_attr_cmd_t report = {0};
report.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
report.clusterID = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF;
report.attributeID = ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID;
report.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
report.zcl_basic_cmd.src_endpoint = ep;

esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_report_attr_cmd_req(&report);
esp_zb_lock_release();

ESP_LOGI(TAG, "EP%d → Report %s", ep, state ? "ON" : "OFF");

}

static void IRAM_ATTR button_isr(void *arg) {
uint32_t gpio_num = (uint32_t) arg;
switch ((gpio_num))
{
case BUTTON1_GPIO:
button_flag[0] = true;
break;
case BUTTON2_GPIO:
button_flag[1] = true;
break;
case BUTTON3_GPIO:
button_flag[2] = true;
break;
case BUTTON4_GPIO:
//ESP_LOGI(TAG, "EP interrupt");
button_flag[3] = true;
break;
default:
break;
}

}

static void button_poll_timer(void *arg)
{
for (int i = 0; i < 4; i++) {
if (button_flag) {
button_flag = false;

Code: Select all

    int btn_gpio = (i == 0) ? BUTTON1_GPIO :
                   (i == 1) ? BUTTON2_GPIO :
                   (i == 2) ? BUTTON3_GPIO :
                              BUTTON4_GPIO;

    if (gpio_get_level(btn_gpio) == 0) {
        relay_state[i] = !relay_state[i];

        int relay_gpio = (i == 0) ? RELAY1_GPIO :
                         (i == 1) ? RELAY2_GPIO :
                         (i == 2) ? RELAY3_GPIO :
                                    RELAY4_GPIO;

        gpio_set_level(relay_gpio, relay_state[i]);

        ESP_LOGI(TAG, "Physical key (io%d)%d → %s",relay_gpio, i + 1,
                 relay_state[i] ? "ON" : "OFF");

        send_onoff_report(i + 1, relay_state[i]);  // endpoint = i+1
    }
}

}

}

// *******************************************************************************
// ZCL Attribute Handlers
// *******************************************************************************

static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *msg)
{
ESP_RETURN_ON_FALSE(msg, ESP_FAIL, TAG, "NULL message");

if (msg->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF &&
msg->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID)
{
uint8_t ep = msg->info.dst_endpoint;
bool new_state = *(bool *)msg->attribute.data.value;

if (ep >= 1 && ep <= 4) {
relay_state[ep - 1] = new_state;

Code: Select all

int relay_gpio = (ep == 1) ? RELAY1_GPIO :
                 (ep == 2) ? RELAY2_GPIO :
                 (ep == 3) ? RELAY3_GPIO :
                             RELAY4_GPIO;

gpio_set_level(relay_gpio, new_state);

}

ESP_LOGI(TAG, "ZCL → EP%d = %s", ep, new_state ? "ON" : "OFF");

}

return ESP_OK;

}

static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t cb_id, const void *msg)
{
switch (cb_id)
{
case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID:
return zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)msg);

case ESP_ZB_CORE_CMD_DEFAULT_RESP_CB_ID:
{
const esp_zb_zcl_cmd_default_resp_message_t *resp =
(const esp_zb_zcl_cmd_default_resp_message_t *)msg;

Code: Select all

ESP_LOGI(TAG,
    "Default response: cl=0x%04X  ep=%d" ,
    resp->info.cluster,
    resp->info.dst_endpoint
);

return ESP_OK;

}
default:
ESP_LOGW(TAG, "Unhandled Zigbee action: %d", cb_id);
return ESP_OK;
}

}
/************************************************

Code: Select all

BDB Callback (Restart Steering)
************************************************/
static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask)
{
esp_zb_bdb_start_top_level_commissioning(mode_mask);
}
// *******************************************************************************
// ZDO / Network Signal Handler
// *******************************************************************************

void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct)
{
uint32_t sig = *(uint32_t *)signal_struct->p_app_signal;
esp_err_t status = signal_struct->esp_err_status;

switch (sig) {

case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP:
ESP_LOGI(TAG, "Initialize Zigbee stack (Tuya compatible)");
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
break;

case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START:
case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT:

Code: Select all

if (status == ESP_OK) {
    ESP_LOGI(TAG, "Factory new: %s",
             esp_zb_bdb_is_factory_new() ? "YES" : "NO");

    if (esp_zb_bdb_is_factory_new()) {
        ESP_LOGI(TAG, "Starting network steering (join to Tuya)");
        esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);

    } else {
        ESP_LOGI(TAG, "Rejoined network.");

    }
} else {
    ESP_LOGW(TAG, "Failed init Zigbee stack: %s", esp_err_to_name(status));
}
break;

case ESP_ZB_BDB_SIGNAL_STEERING:
if (status == ESP_OK) {
esp_zb_ieee_addr_t panid;
esp_zb_get_extended_pan_id(panid);
ESP_LOGI(TAG,
"Joined Tuya Gateway\n"
"PAN ID: 0x%04hx\n"
"Channel: %d\n"
"ShortAddr: 0x%04hx",
esp_zb_get_pan_id(),
esp_zb_get_current_channel(),
esp_zb_get_short_address());

Code: Select all

} else {
    ESP_LOGW(TAG, "Steering failed  retrying...");
    esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb,
                           ESP_ZB_BDB_MODE_NETWORK_STEERING,
                           2000);
}
break;

default:
ESP_LOGI(TAG, "ZDO signal: %s", esp_zb_zdo_signal_to_string(sig));
break;
}

}

// *******************************************************************************
// Zigbee Task
// *******************************************************************************
static void zigbee_task(void *arg)
{
gpio_set_direction(RELAY1_GPIO, GPIO_MODE_OUTPUT);
gpio_set_direction(RELAY2_GPIO, GPIO_MODE_OUTPUT);
gpio_set_direction(RELAY3_GPIO, GPIO_MODE_OUTPUT);
gpio_set_direction(RELAY4_GPIO, GPIO_MODE_OUTPUT);

gpio_set_level(RELAY1_GPIO, 0);
gpio_set_level(RELAY2_GPIO, 0);
gpio_set_level(RELAY3_GPIO, 0);
gpio_set_level(RELAY4_GPIO, 0);

// Zigbee End Device Config
esp_zb_cfg_t zb_cfg = ESP_ZB_ZED_CONFIG(); // END DEVICE
esp_zb_init(&zb_cfg);
esp_zb_set_primary_network_channel_set(ALL_ZIGBEE_CHANNELS);

// common attrs for Basic cluster
uint8_t zcl_ver = 3;
uint8_t pwr_src = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE;

// ------------------ BUILD CLUSTERS FOR ENDPOINT 1 ------------------
esp_zb_attribute_list_t *basic1 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_BASIC);
esp_zb_basic_cluster_add_attr(basic1, ESP_ZB_ZCL_ATTR_BASIC_APPLICATION_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic1, ESP_ZB_ZCL_ATTR_BASIC_STACK_VERSION_ID, &(uint8_t){2});
esp_zb_basic_cluster_add_attr(basic1, ESP_ZB_ZCL_ATTR_BASIC_HW_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic1, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, "ESP32");
esp_zb_basic_cluster_add_attr(basic1, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, "ZB-RELAY-1");
esp_zb_basic_cluster_add_attr(basic1, ESP_ZB_ZCL_ATTR_BASIC_ZCL_VERSION_ID, &zcl_ver);
esp_zb_basic_cluster_add_attr(basic1, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, &pwr_src);

esp_zb_attribute_list_t *identify1 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY);
esp_zb_identify_cluster_add_attr(identify1, ESP_ZB_ZCL_ATTR_IDENTIFY_IDENTIFY_TIME_ID, &(uint16_t){0});

esp_zb_attribute_list_t *groups1 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS);
esp_zb_groups_cluster_add_attr(groups1, ESP_ZB_ZCL_ATTR_GROUPS_NAME_SUPPORT_ID, &(uint8_t){0});

esp_zb_attribute_list_t *scenes1 = esp_zb_scenes_cluster_create(NULL);

esp_zb_on_off_cluster_cfg_t onoff_cfg1 = { .on_off = false };
esp_zb_attribute_list_t *onoff1 = esp_zb_on_off_cluster_create(&onoff_cfg1);

esp_zb_cluster_list_t cluster_list1 = esp_zb_zcl_cluster_list_create();
esp_zb_cluster_list_add_basic_cluster(cluster_list1, basic1, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_identify_cluster(cluster_list1, identify1, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_groups_cluster(cluster_list1, groups1, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_scenes_cluster(cluster_list1, scenes1, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_on_off_cluster(cluster_list1, onoff1, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
/
client clusters required by some hubs (Tuya) */
// esp_zb_cluster_list_add_identify_cluster(cluster_list1, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_groups_cluster(cluster_list1, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_scenes_cluster(cluster_list1, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_SCENES), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_on_off_cluster(cluster_list1, esp_zb_on_off_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);

// ------------------ BUILD CLUSTERS FOR ENDPOINT 2 ------------------
esp_zb_attribute_list_t *basic2 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_BASIC);
esp_zb_basic_cluster_add_attr(basic2, ESP_ZB_ZCL_ATTR_BASIC_APPLICATION_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic2, ESP_ZB_ZCL_ATTR_BASIC_STACK_VERSION_ID, &(uint8_t){2});
esp_zb_basic_cluster_add_attr(basic2, ESP_ZB_ZCL_ATTR_BASIC_HW_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic2, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, "ESP32");
esp_zb_basic_cluster_add_attr(basic2, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, "ZB-RELAY-2");
esp_zb_basic_cluster_add_attr(basic2, ESP_ZB_ZCL_ATTR_BASIC_ZCL_VERSION_ID, &zcl_ver);
esp_zb_basic_cluster_add_attr(basic2, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, &pwr_src);

esp_zb_attribute_list_t *identify2 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY);
esp_zb_identify_cluster_add_attr(identify2, ESP_ZB_ZCL_ATTR_IDENTIFY_IDENTIFY_TIME_ID, &(uint16_t){0});

esp_zb_attribute_list_t *groups2 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS);
esp_zb_groups_cluster_add_attr(groups2, ESP_ZB_ZCL_ATTR_GROUPS_NAME_SUPPORT_ID, &(uint8_t){0});

esp_zb_attribute_list_t *scenes2 = esp_zb_scenes_cluster_create(NULL);

esp_zb_on_off_cluster_cfg_t onoff_cfg2 = { .on_off = false };
esp_zb_attribute_list_t *onoff2 = esp_zb_on_off_cluster_create(&onoff_cfg2);

esp_zb_cluster_list_t cluster_list2 = esp_zb_zcl_cluster_list_create();
esp_zb_cluster_list_add_basic_cluster(cluster_list2, basic2, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_identify_cluster(cluster_list2, identify2, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_groups_cluster(cluster_list2, groups2, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_scenes_cluster(cluster_list2, scenes2, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_on_off_cluster(cluster_list2, onoff2, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
/
client clusters */
// esp_zb_cluster_list_add_identify_cluster(cluster_list2, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_groups_cluster(cluster_list2, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_scenes_cluster(cluster_list2, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_SCENES), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_on_off_cluster(cluster_list2, esp_zb_on_off_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);

// ------------------ BUILD CLUSTERS FOR ENDPOINT 3 ------------------
esp_zb_attribute_list_t *basic3 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_BASIC);
esp_zb_basic_cluster_add_attr(basic3, ESP_ZB_ZCL_ATTR_BASIC_APPLICATION_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic3, ESP_ZB_ZCL_ATTR_BASIC_STACK_VERSION_ID, &(uint8_t){2});
esp_zb_basic_cluster_add_attr(basic3, ESP_ZB_ZCL_ATTR_BASIC_HW_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic3, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, "ESP32");
esp_zb_basic_cluster_add_attr(basic3, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, "ZB-RELAY-3");
esp_zb_basic_cluster_add_attr(basic3, ESP_ZB_ZCL_ATTR_BASIC_ZCL_VERSION_ID, &zcl_ver);
esp_zb_basic_cluster_add_attr(basic3, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, &pwr_src);

esp_zb_attribute_list_t *identify3 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY);
esp_zb_identify_cluster_add_attr(identify3, ESP_ZB_ZCL_ATTR_IDENTIFY_IDENTIFY_TIME_ID, &(uint16_t){0});

esp_zb_attribute_list_t *groups3 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS);
esp_zb_groups_cluster_add_attr(groups3, ESP_ZB_ZCL_ATTR_GROUPS_NAME_SUPPORT_ID, &(uint8_t){0});

esp_zb_attribute_list_t *scenes3 = esp_zb_scenes_cluster_create(NULL);

esp_zb_on_off_cluster_cfg_t onoff_cfg3 = { .on_off = false };
esp_zb_attribute_list_t *onoff3 = esp_zb_on_off_cluster_create(&onoff_cfg3);

esp_zb_cluster_list_t cluster_list3 = esp_zb_zcl_cluster_list_create();
esp_zb_cluster_list_add_basic_cluster(cluster_list3, basic3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_identify_cluster(cluster_list3, identify3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_groups_cluster(cluster_list3, groups3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_scenes_cluster(cluster_list3, scenes3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_on_off_cluster(cluster_list3, onoff3, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
/
client clusters */
// esp_zb_cluster_list_add_identify_cluster(cluster_list3, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_groups_cluster(cluster_list3, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_scenes_cluster(cluster_list3, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_SCENES), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_on_off_cluster(cluster_list3, esp_zb_on_off_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);

// ------------------ BUILD CLUSTERS FOR ENDPOINT 4 ------------------
esp_zb_attribute_list_t *basic4 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_BASIC);
esp_zb_basic_cluster_add_attr(basic4, ESP_ZB_ZCL_ATTR_BASIC_APPLICATION_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic4, ESP_ZB_ZCL_ATTR_BASIC_STACK_VERSION_ID, &(uint8_t){2});
esp_zb_basic_cluster_add_attr(basic4, ESP_ZB_ZCL_ATTR_BASIC_HW_VERSION_ID, &(uint8_t){1});
esp_zb_basic_cluster_add_attr(basic4, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, "ESP32");
esp_zb_basic_cluster_add_attr(basic4, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, "ZB-RELAY-4");
esp_zb_basic_cluster_add_attr(basic4, ESP_ZB_ZCL_ATTR_BASIC_ZCL_VERSION_ID, &zcl_ver);
esp_zb_basic_cluster_add_attr(basic4, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, &pwr_src);

esp_zb_attribute_list_t *identify4 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY);
esp_zb_identify_cluster_add_attr(identify4, ESP_ZB_ZCL_ATTR_IDENTIFY_IDENTIFY_TIME_ID, &(uint16_t){0});

esp_zb_attribute_list_t *groups4 = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS);
esp_zb_groups_cluster_add_attr(groups4, ESP_ZB_ZCL_ATTR_GROUPS_NAME_SUPPORT_ID, &(uint8_t){0});

esp_zb_attribute_list_t *scenes4 = esp_zb_scenes_cluster_create(NULL);

esp_zb_on_off_cluster_cfg_t onoff_cfg4 = { .on_off = false };
esp_zb_attribute_list_t *onoff4 = esp_zb_on_off_cluster_create(&onoff_cfg4);

esp_zb_cluster_list_t cluster_list4 = esp_zb_zcl_cluster_list_create();
esp_zb_cluster_list_add_basic_cluster(cluster_list4, basic4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_identify_cluster(cluster_list4, identify4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_groups_cluster(cluster_list4, groups4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_scenes_cluster(cluster_list4, scenes4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_on_off_cluster(cluster_list4, onoff4, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
/
client clusters */
// esp_zb_cluster_list_add_identify_cluster(cluster_list4, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_groups_cluster(cluster_list4, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_GROUPS), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_scenes_cluster(cluster_list4, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_SCENES), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
// esp_zb_cluster_list_add_on_off_cluster(cluster_list4, esp_zb_on_off_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);

// ------------------- Endpoint list ----------------------
esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create();

esp_zb_endpoint_config_t ep1_cfg = {
.endpoint = EP_SWITCH1,
.app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
.app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
.app_device_version = 1
};
esp_zb_ep_list_add_ep(ep_list, cluster_list1, ep1_cfg);

esp_zb_endpoint_config_t ep2_cfg = {
.endpoint = EP_SWITCH2,
.app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
.app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
.app_device_version = 1
};
esp_zb_ep_list_add_ep(ep_list, cluster_list2, ep2_cfg);

esp_zb_endpoint_config_t ep3_cfg = {
.endpoint = EP_SWITCH3,
.app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
.app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
.app_device_version = 1
};
esp_zb_ep_list_add_ep(ep_list, cluster_list3, ep3_cfg);

esp_zb_endpoint_config_t ep4_cfg = {
.endpoint = EP_SWITCH4,
.app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
.app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
.app_device_version = 1
};
esp_zb_ep_list_add_ep(ep_list, cluster_list4, ep4_cfg);

esp_zb_device_register(ep_list);

// register handler و start
esp_zb_core_action_handler_register(zb_action_handler);

ESP_ERROR_CHECK(esp_zb_start(false));
esp_zb_stack_main_loop();

}

// *******************************************************************************
// app_main
// *******************************************************************************

void app_main(void)
{
esp_log_level_set("*", ESP_LOG_DEBUG);
ESP_ERROR_CHECK(nvs_flash_init());
button_queue = xQueueCreate(4, sizeof(uint8_t));

esp_zb_platform_config_t config = {
.radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_ZB_DEFAULT_HOST_CONFIG(),
};

ESP_ERROR_CHECK(esp_zb_platform_config(&config));

gpio_config_t io_conf1 = {
.pin_bit_mask = 1ULL << BUTTON1_GPIO,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.intr_type = GPIO_INTR_NEGEDGE
};
gpio_config(&io_conf1);

gpio_config_t io_conf2 = {
.pin_bit_mask = 1ULL << BUTTON2_GPIO,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.intr_type = GPIO_INTR_NEGEDGE
};
gpio_config(&io_conf2);
gpio_config_t io_conf3 = {
.pin_bit_mask = 1ULL << BUTTON3_GPIO,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.intr_type = GPIO_INTR_NEGEDGE
};
gpio_config(&io_conf3);
gpio_config_t io_conf4 = {
.pin_bit_mask = 1ULL << BUTTON4_GPIO,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.intr_type = GPIO_INTR_NEGEDGE
};
gpio_config(&io_conf4)
;
gpio_install_isr_service(0);
gpio_isr_handler_add(BUTTON1_GPIO, button_isr, (void)BUTTON1_GPIO);
gpio_isr_handler_add(BUTTON2_GPIO, button_isr, (void
)BUTTON2_GPIO);
gpio_isr_handler_add(BUTTON3_GPIO, button_isr, (void)BUTTON3_GPIO);
gpio_isr_handler_add(BUTTON4_GPIO, button_isr, (void
)BUTTON4_GPIO);

esp_timer_handle_t btn_timer;
const esp_timer_create_args_t btn_args = {
.callback = &button_poll_timer,
.name = "button_timer"
};
esp_timer_create(&btn_args, &btn_timer);
esp_timer_start_periodic(btn_timer, 20 * 1000);

xTaskCreate(zigbee_task, "zigbee_task", 4096, NULL, 5, NULL);

}

Post Reply