espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.65k stars 7.41k forks source link

Need Multiple light examples for HA on off light #10240

Open sonirohit3 opened 2 months ago

sonirohit3 commented 2 months ago

Board

ESP32-C6

Device Description

image image

Hardware Configuration

Custom Board

Version

latest master (checkout manually)

IDE Name

Arduino IDE

Operating System

Windows 11

Flash frequency

80 MHz

PSRAM enabled

no

Upload speed

115200

Description

I am trying to create multiple endpoints on Zigbee but only 1st endpoints are detected.

Sketch

// Copyright 2023 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @brief This example demonstrates simple Zigbee light bulb.
 *
 * The example demonstrates how to use ESP Zigbee stack to create a end device light bulb.
 * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator.
 *
 * Proper Zigbee mode must be selected in Tools->Zigbee mode
 * and also the correct partition scheme must be selected in Tools->Partition Scheme.
 *
 * Please check the README.md for instructions and more detailed description.
 */

#ifndef ZIGBEE_MODE_ED
#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
#endif

#include "esp_zigbee_core.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ha/esp_zigbee_ha_standard.h"

#define LED_PIN RGB_BUILTIN

/* Default End Device config */
#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 = ED_AGING_TIMEOUT,                                                   \
          .keep_alive = ED_KEEP_ALIVE,                                                      \
        },                                                                                  \
    },                                                                                      \
  }

#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, }

/* Zigbee configuration */
#define INSTALLCODE_POLICY_ENABLE   false /* enable the install code policy for security */
#define ED_AGING_TIMEOUT            ESP_ZB_ED_AGING_TIMEOUT_64MIN
#define ED_KEEP_ALIVE               3000                                 /* 3000 millisecond */
#define HA_ESP_LIGHT_ENDPOINT       10                                   /* esp light bulb device endpoint, used to process light controlling commands */

// FIXME: This needs fixing
#define HA_ESP_LIGHT_ENDPOINT_2     11  /* Unique endpoint for the second light bulb (change according to application requirement)*/

#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */

/********************* Zigbee functions **************************/
static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) {
  ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask));
}

void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
  uint32_t *p_sg_p = signal_struct->p_app_signal;
  esp_err_t err_status = signal_struct->esp_err_status;
  esp_zb_app_signal_type_t sig_type = (esp_zb_app_signal_type_t)*p_sg_p;
  switch (sig_type) {
    case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP:
      log_i("Zigbee stack initialized");
      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:
      if (err_status == ESP_OK) {
        log_i("Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non");
        if (esp_zb_bdb_is_factory_new()) {
          log_i("Start network formation");
          esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
        } else {
          log_i("Device rebooted");
        }
      } else {
        /* commissioning failed */
        log_w("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status));
      }
      break;
    case ESP_ZB_BDB_SIGNAL_STEERING:
      if (err_status == ESP_OK) {
        esp_zb_ieee_addr_t extended_pan_id;
        esp_zb_get_extended_pan_id(extended_pan_id);
        log_i(
          "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)",
          extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4], extended_pan_id[3], extended_pan_id[2], extended_pan_id[1],
          extended_pan_id[0], esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address()
        );
      } else {
        log_i("Network steering was not successful (status: %s)", esp_err_to_name(err_status));
        esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
      }
      break;
    default: log_i("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); break;
  }
}

static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message) {
  esp_err_t ret = ESP_OK;
  switch (callback_id) {
    case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID: 
          ret = zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)message); 
          break;
    default:                               
          log_w("Receive Zigbee action(0x%x) callback", callback_id); break;
  }
  return ret;
}

static void esp_zb_task(void *pvParameters) {
  esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG();
  esp_zb_init(&zb_nwk_cfg);

  // Configure first light endpoint
  esp_zb_on_off_light_cfg_t light_cfg = ESP_ZB_DEFAULT_ON_OFF_LIGHT_CONFIG();
  esp_zb_ep_list_t *esp_zb_on_off_light_ep = esp_zb_on_off_light_ep_create(HA_ESP_LIGHT_ENDPOINT, &light_cfg);
  esp_zb_device_register(esp_zb_on_off_light_ep);

  // Configure second light endpoint // FIXME: This needs fixing according to apploication needs
  esp_zb_on_off_light_cfg_t light_cfg_2 = ESP_ZB_DEFAULT_ON_OFF_LIGHT_CONFIG();
  esp_zb_ep_list_t *esp_zb_on_off_light_ep_2 = esp_zb_on_off_light_ep_create(HA_ESP_LIGHT_ENDPOINT_2, &light_cfg_2);
  esp_zb_device_register(esp_zb_on_off_light_ep_2);

  esp_zb_core_action_handler_register(zb_action_handler);
  esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK);

  //Erase NVRAM before creating connection to new Coordinator
  esp_zb_nvram_erase_at_start(true);  //Comment out this line to erase NVRAM data if you are conneting to new Coordinator

  ESP_ERROR_CHECK(esp_zb_start(false));
  esp_zb_main_loop_iteration();
}

/* Handle the light attribute */

static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message) {
  esp_err_t ret = ESP_OK;
  bool light_state = 0;

  if (!message) {
    log_e("Empty message");
  }
  if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
    log_e("Received message: error status(%d)", message->info.status);
  }

  log_i(
    "Received message: endpoint(%d), cluster(0x%x), attribute(0x%x), data size(%d)", message->info.dst_endpoint, message->info.cluster, message->attribute.id,
    message->attribute.data.size
  );

  // Handle the first endpoint
  if (message->info.dst_endpoint == HA_ESP_LIGHT_ENDPOINT) {
    if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
      if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) {
        light_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : light_state;
        log_i("Light 1 sets to %s", light_state ? "On" : "Off");
        neopixelWrite(LED_PIN, 255 * light_state, 0* light_state, 255 * light_state);  // Toggle light
      }
    }
  }
  // Handle the second endpoint
  if (message->info.dst_endpoint == HA_ESP_LIGHT_ENDPOINT_2) {
    if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
        if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) {
          light_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : light_state;
          log_i("Light 2 sets to %s", light_state ? "On" : "Off");
           // FIXME: Change LED_PIN to some other pins.
           neopixelWrite(LED_PIN, 0* light_state, 255 * light_state, 255 * light_state);  // Toggle light
        }
    }
  }
  return ret;
}

/********************* Arduino functions **************************/
void setup() {
  // Init Zigbee
  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));

  // Init RMT and leave light OFF
  neopixelWrite(LED_PIN, 0, 0, 0);

  // Start Zigbee task
  xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL);
}

void loop() {
  //empty, zigbee running in task
}

Debug Message

ESP-ROM:esp32c6-20220919<CR><LF>
Build:Sep 19 2022<CR><LF>
rst:0x1 (POWERON),boot:0x6c (SPI_FAST_FLASH_BOOT)<CR><LF>
SPIWP:0xee<CR><LF>
mode:DIO, clock div:2<CR><LF>
load:0x4086c410,len:0xcf8<CR><LF>
load:0x4086e610,len:0x2e44<CR><LF>
load:0x40875728,len:0x113c<CR><LF>
entry 0x4086c410<CR><LF>
[   141][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RX (2) successfully set to 0x42003ff4<CR><LF>
[   153][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_TX (3) successfully set to 0x42003fb8<CR><LF>
[   164][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_CTS (4) successfully set to 0x42003f7c<CR><LF>
[   175][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RTS (5) successfully set to 0x42003f40<CR><LF>
[   187][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RX (2) successfully set to 0x42003ff4<CR><LF>
[   198][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_TX (3) successfully set to 0x42003fb8<CR><LF>
[   209][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_CTS (4) successfully set to 0x42003f7c<CR><LF>
[   221][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RTS (5) successfully set to 0x42003f40<CR><LF>
[   238][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 17 successfully set to type UART_RX (2) with bus 0x4080e148<CR><LF>
[   249][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 16 successfully set to type UART_TX (3) with bus 0x4080e148<CR><LF>
=========== Before Setup Start ===========<CR><LF>
Chip Info:<CR><LF>
------------------------------------------<CR><LF>
  Model             : ESP32-C6<CR><LF>
  Package           : 0<CR><LF>
  Revision          : 0<CR><LF>
  Cores             : 1<CR><LF>
  CPU Frequency     : 160 MHz<CR><LF>
  XTAL Frequency    : 40 MHz<CR><LF>
  Features Bitfield : 0x00000052<CR><LF>
  Embedded Flash    : No<CR><LF>
  Embedded PSRAM    : No<CR><LF>
  2.4GHz WiFi       : Yes<CR><LF>
  Classic BT        : No<CR><LF>
  BT Low Energy     : Yes<CR><LF>
  IEEE 802.15.4     : Yes<CR><LF>
------------------------------------------<CR><LF>
INTERNAL Memory Info:<CR><LF>
------------------------------------------<CR><LF>
  Total Size        :   450956 B ( 440.4 KB)<CR><LF>
  Free Bytes        :   417464 B ( 407.7 KB)<CR><LF>
  Allocated Bytes   :    27228 B (  26.6 KB)<CR><LF>
  Minimum Free Bytes:   417280 B ( 407.5 KB)<CR><LF>
  Largest Free Block:   401396 B ( 392.0 KB)<CR><LF>
------------------------------------------<CR><LF>
Flash Info:<CR><LF>
------------------------------------------<CR><LF>
  Chip Size         :  8388608 B (8 MB)<CR><LF>
  Block Size        :    65536 B (  64.0 KB)<CR><LF>
  Sector Size       :     4096 B (   4.0 KB)<CR><LF>
  Page Size         :      256 B (   0.2 KB)<CR><LF>
  Bus Speed         : 40 MHz<CR><LF>
  Bus Mode          : QIO<CR><LF>
------------------------------------------<CR><LF>
Partitions Info:<CR><LF>
------------------------------------------<CR><LF>
                nvs : addr: 0x00009000, size:    20.0 KB, type: DATA, subtype: NVS<CR><LF>
            otadata : addr: 0x0000E000, size:     8.0 KB, type: DATA, subtype: OTA<CR><LF>
               app0 : addr: 0x00010000, size:  1280.0 KB, type:  APP, subtype: OTA_0<CR><LF>
               app1 : addr: 0x00150000, size:  1280.0 KB, type:  APP, subtype: OTA_1<CR><LF>
             spiffs : addr: 0x00290000, size:  1388.0 KB, type: DATA, subtype: SPIFFS<CR><LF>
         zb_storage : addr: 0x003EB000, size:    16.0 KB, type: DATA, subtype: FAT<CR><LF>
             zb_fct : addr: 0x003EF000, size:     4.0 KB, type: DATA, subtype: FAT<CR><LF>
           coredump : addr: 0x003F0000, size:    64.0 KB, type: DATA, subtype: COREDUMP<CR><LF>
------------------------------------------<CR><LF>
Software Info:<CR><LF>
------------------------------------------<CR><LF>
  Compile Date/Time : Aug 26 2024 00:17:09<CR><LF>
  Compile Host OS   : windows<CR><LF>
  ESP-IDF Version   : v5.1.4-586-gb6b4727c58-dirty<CR><LF>
  Arduino Version   : 3.0.4<CR><LF>
------------------------------------------<CR><LF>
Board Info:<CR><LF>
------------------------------------------<CR><LF>
  Arduino Board     : ESP32C6_DEV<CR><LF>
  Arduino Variant   : esp32c6<CR><LF>
  Arduino FQBN      : esp32:esp32:esp32c6:UploadSpeed=921600,CDCOnBoot=default,CPUFreq=160,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=zigbee,DebugLevel=verbose,EraseFlash=all,JTAGAdapter=default,ZigbeeMode=ed<CR><LF>
============ Before Setup End ============<CR><LF>
[   590][V][esp32-hal-rmt.c:454] rmtInit(): GPIO 8 - TX MODE - MemSize[48] - Freq=10000000Hz<CR><LF>
[   598][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type RMT_TX (10) successfully set to 0x420010a4<CR><LF>
[   610][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type RMT_RX (11) successfully set to 0x420010a4<CR><LF>
[   621][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 8 successfully set to type RMT_TX (10) with bus 0x4087f4f8<CR><LF>
[   633][V][esp32-hal-rmt.c:305] _rmtWrite(): GPIO: 8 - Request: 24 RMT Symbols - Blocking - Timeout: -1<CR><LF>
[   642][V][esp32-hal-rmt.c:306] _rmtWrite(): GPIO: 8 - Currently in Loop Mode: [NO] | Asked to Loop: NO, LoopCancel: NO<CR><LF>
=========== After Setup Start ============<CR><LF>
INTERNAL Memory Info:<CR><LF>
------------------------------------------<CR><LF>
  Total Size        :   450956 B ( 440.4 KB)<CR><LF>
[   784][I][Zigbee_Light_Bulb_Updated.ino:112] esp_zb_app_signal_handler(): ZDO signal: ZDO Config Ready (0x17), status: ESP_FAIL<CR><LF>
[   797][I][Zigbee_Light_Bulb_Updated.ino:80] esp_zb_app_signal_handler(): Zigbee stack initialized<CR><LF>
[   807][I][Zigbee_Light_Bulb_Updated.ino:86] esp_zb_app_signal_handler(): Device started up in  factory-reset mode<CR><LF>
[   817][I][Zigbee_Light_Bulb_Updated.ino:88] esp_zb_app_signal_handler(): Start network formation<CR><LF>
  Free Bytes        :   392436 B ( 383.2 KB)<CR><LF>
  Allocated Bytes   :    50376 B (  49.2 KB)<CR><LF>
  Minimum Free Bytes:   391008 B ( 381.8 KB)<CR><LF>
  Largest Free Block:   368628 B ( 360.0 KB)<CR><LF>
------------------------------------------<CR><LF>
GPIO Info:<CR><LF>
------------------------------------------<CR><LF>
  GPIO : BUS_TYPE[bus/unit][chan]<CR><LF>
  --------------------------------------  <CR><LF>
     8 : RMT_TX<CR><LF>
    16 : UART_TX[0]<CR><LF>
    17 : UART_RX[0]<CR><LF>
============ After Setup End =============<CR><LF>

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

P-R-O-C-H-Y commented 2 months ago

Hi @sonirohit3, I am now working on the Zigbee library for ESP Arduino. Follow issue #10135 for more details. With the code you are using you can ask for help on esp-zigbee-sdk repository :) Thanks

sonirohit3 commented 2 months ago

Hi Prochy, Thanks for the information. I will keep track of this. It would be really nice if somehow, I can get the sample code for multiple endpoints early. I have the hardware ready.

Regards, Rohit Soni

VojtechBartoska commented 2 months ago

FIY: Those deleted comments have been from some bot with suspicious content.

sonirohit3 commented 2 months ago

Hi @P-R-O-C-H-Y , I am now able to add multiple endpoints and the same are detected on the HA. This device has onboard switch from which I can toggle the LED. I need suggestion on how I can update the same to the HA server when LED is toggled with a physical switch. Below is my sample code. This creates a light and a Smart plug on HA.

Zigbee_Light_Bulb_Updated.zip

P-R-O-C-H-Y commented 2 months ago

@sonirohit3 Can you please format the code in the comment so its readable? Thanks

sonirohit3 commented 2 months ago

@sonirohit3 Can you please format the code in the comment so its readable? Thanks

Certainly! Edited my previous comment and attached the INO file in compressed zip. I am also trying to see how a fan type device can be implemented in this. The device has rotary encoder which can we used to increase / decrease fan speed. Any suggestion on this?

sonirohit3 commented 2 months ago

Hi @P-R-O-C-H-Y , Any suggestion on above? Please suggest how to modify the light bulb example code to add a switch and send back the updated status to HA when toggled.

P-R-O-C-H-Y commented 1 month ago

Hi @sonirohit3, you will need to set the attribute value using

esp_zb_zcl_status_t esp_zb_zcl_set_attribute_val(uint8_t endpoint, uint16_t cluster_id, uint8_t cluster_role, uint16_t attr_id, void *value_p, bool check);

For more info take a look here