Why my zigbee resets in loop when USB is not plugged

Hello,

Using ESP32C6 I have my device working well when USB is connected. Battery is charging too. It sends temperature over zigbee and goes to deep sleep as expected. It also wakes up every 5 min to do that every 5 min as expected.

If I unplug USB, this continues working perfectly.

But, if I power off/on using battery wires, or if I press the reset button, then the device loops resetting. Taking traces on UART TX pin, the restart occurs after message saying zigbee stack is initialized.

Replugging USB solves the issue immediately. And again, all goes well, waking up from deep sleep every 5 min, even if I unplug USB for hours. Until I’d power cycle or reset.

I am building with Arduino IDE.

To have trace on UART, I added serial0.println(). I observe log_i() calls may be the root cause. I removed them all from my code, but may be some API calls are still causing calls to log_*().
I fear I do not know how to build for support of unplugged USB.

Thank you for ideas

Michel

Hi there,
And Welcome here, So can you post the code you are trying, use the code tags above"</>" and paste it in there, Lots of smart folks here can help.
GL :slight_smile: PJ :v:

which BSP are you using to do this. Current one is 3.0.5 you may need to roll back and try that. :+1:

Thank you for the feedback.
Actually BSP was 3.1.0-RC1. I rolledback to 3.0.5. Unfortunately, phenomenon remains unchanged.

Here is code:

// Copyright 2024 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.

static const char *TAG = "ESP_ZB_DEEP_SLEEP";

/**
 * @brief This example demonstrates simple Zigbee temperature sensor.
 *
 * The example demonstrates how to use ESP Zigbee stack to create a end device temperature sensor.
 * The temperature sensor 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"
//#include <SoftwareSerial.h>

// RX pin, TX pin
//SoftwareSerial Serial0(D7, D6);


static RTC_DATA_ATTR struct timeval s_sleep_enter_time;
static esp_timer_handle_t s_oneshot_timer;

// FOR DALLAS
#include "OneWire.h"
#include "DallasTemperature.h"
// Define to which pin of the Arduino the 1-Wire bus is connected:
#define ONE_WIRE_BUS 2


/* Switch configuration */
#define GPIO_INPUT_IO_TOGGLE_SWITCH GPIO_NUM_9
#define PAIR_SIZE(TYPE_STR_PAIR)    (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0]))

typedef enum {
  SWITCH_ON_CONTROL,
  SWITCH_OFF_CONTROL,
  SWITCH_ONOFF_TOGGLE_CONTROL,
  SWITCH_LEVEL_UP_CONTROL,
  SWITCH_LEVEL_DOWN_CONTROL,
  SWITCH_LEVEL_CYCLE_CONTROL,
  SWITCH_COLOR_CONTROL,
} switch_func_t;

typedef struct {
  uint8_t pin;
  switch_func_t func;
} switch_func_pair_t;

typedef enum {
  SWITCH_IDLE,
  SWITCH_PRESS_ARMED,
  SWITCH_PRESS_DETECTED,
  SWITCH_PRESSED,
  SWITCH_RELEASE_DETECTED,
} switch_state_t;

static switch_func_pair_t button_func_pair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}};

/* 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               4000                                 /* 3000 millisecond */
#define HA_ESP_SENSOR_ENDPOINT      10                                   /* esp temperature sensor device endpoint, used for temperature measurement */
#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */

/* Temperature sensor configuration */
#define ESP_TEMP_SENSOR_UPDATE_INTERVAL (1)  /* Local sensor update interval (second) */
//#define ESP_TEMP_SENSOR_MIN_VALUE       (10) /* Local sensor min measured value (degree Celsius) */
//#define ESP_TEMP_SENSOR_MAX_VALUE       (50) /* Local sensor max measured value (degree Celsius) */
#define POOL_TEMP_SENSOR_MIN_VALUE (-30)
#define POOL_TEMP_SENSOR_MAX_VALUE (55)

/* Attribute values in ZCL string format
 * The string should be started with the length of its own.
 */
#define MANUFACTURER_NAME \
  "\x0B"                  \
  "ESPRESSIF-------"
#define MODEL_IDENTIFIER "\x09" CONFIG_IDF_TARGET "-------"

SemaphoreHandle_t msu_ConnectionSem;

/********************* Zigbee functions **************************/
static int16_t zb_temperature_to_s16(float temp) {
  return (int16_t)(temp * 100);
}

static void esp_zb_buttons_handler(switch_func_pair_t *button_func_pair) {
  if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) {
    /* Send report attributes command */
    esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
    report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
    report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
    report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
    report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
    report_attr_cmd.zcl_basic_cmd.src_endpoint = HA_ESP_SENSOR_ENDPOINT;

    esp_zb_lock_acquire(portMAX_DELAY);
    esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
    esp_zb_lock_release();
    Serial0.println("Send 'report attributes' command");
  }
}

static void esp_app_temp_sensor_handler(float temperature) {
  int16_t measured_value = zb_temperature_to_s16(temperature);
  Serial0.println("Updating temperature sensor value...");
  Serial0.println(measured_value);
  /* Update temperature sensor measured value */
  esp_zb_lock_acquire(portMAX_DELAY);
  esp_zb_zcl_set_attribute_val(
    HA_ESP_SENSOR_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &measured_value,
    false
  );
  esp_zb_lock_release();

  Serial0.println("Report temp sensor reading");
  esp_zb_zcl_report_attr_cmd_t cmd_req2;
  cmd_req2.zcl_basic_cmd.dst_endpoint = 1; // HA_ESP_LIGHT_ENDPOINT;
  cmd_req2.zcl_basic_cmd.src_endpoint = HA_ESP_SENSOR_ENDPOINT;
  cmd_req2.zcl_basic_cmd.dst_addr_u.addr_short = 0x0000;
  cmd_req2.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
  cmd_req2.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
  cmd_req2.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
  cmd_req2.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
  esp_zb_lock_acquire(portMAX_DELAY);
  ESP_ERROR_CHECK_WITHOUT_ABORT(esp_zb_zcl_report_attr_cmd_req(&cmd_req2));
  esp_zb_lock_release();
  Serial0.println("Reports sent");
}

static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) {
  ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask));
}

static void zb_deep_sleep_start(void)
{
    /* Start the one-shot timer */
    const int before_deep_sleep_time_sec = 5;
    ESP_LOGI(TAG, "Start one-shot timer for %ds to enter the deep sleep", before_deep_sleep_time_sec);
    ESP_ERROR_CHECK(esp_timer_start_once(s_oneshot_timer, before_deep_sleep_time_sec * 1000000));
}

uint8_t stackInitTrial = 0;

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:
      Serial0.println("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) {
        Serial0.println("Start network steering");

        // Start Temperature sensor reading task. 
        xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 4, NULL);

        if (esp_zb_bdb_is_factory_new()) {
          Serial0.println("Start Net Steering - fact new");
          esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
        } else {
          Serial0.println("deep sleep start - fact NOT new");
          zb_deep_sleep_start(); // starts 5s timer before sleep
          Serial0.println("Device rebooted");
        }
      } else {
        /* commissioning failed */
        Serial0.println("Init stak failed");
        Serial0.print("Failed to initialize Zigbee stack. Status:");
        Serial0.println(esp_err_to_name(err_status));
        if(++stackInitTrial > 5) {
          esp_deep_sleep_start(); // Will try again later
        } else {
          esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
        }
      }
      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()
        //);
        Serial0.println("Joined");
        // Allow temperature task to send data
        //xSemaphoreGive(msu_ConnectionSem);

        //connected = 1;
      } else {
        Serial0.println("Fail steering");
        Serial0.print("Network steering was not successful:");
        Serial0.println(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;
    case ESP_ZB_COMMON_SIGNAL_CAN_SLEEP:
      Serial0.println("Can sleep");
      break;
    default: 
      Serial0.print("Unk signal:");
      Serial0.print(sig_type);
      Serial0.print("=");
      Serial0.println(esp_zb_zdo_signal_to_string(sig_type));
      Serial0.print(" err=");
      Serial0.println(esp_err_to_name(err_status)); 
      break;
  }
}

static esp_zb_cluster_list_t *custom_temperature_sensor_clusters_create(esp_zb_temperature_sensor_cfg_t *temperature_sensor) {
  esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();
  esp_zb_attribute_list_t *basic_cluster = esp_zb_basic_cluster_create(&(temperature_sensor->basic_cfg));
  ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)MANUFACTURER_NAME));
  ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)MODEL_IDENTIFIER));
  ESP_ERROR_CHECK(esp_zb_cluster_list_add_basic_cluster(cluster_list, basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE));
  ESP_ERROR_CHECK(
    esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(&(temperature_sensor->identify_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE)
  );
  ESP_ERROR_CHECK(
    esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE)
  );
  ESP_ERROR_CHECK(esp_zb_cluster_list_add_temperature_meas_cluster(
    cluster_list, esp_zb_temperature_meas_cluster_create(&(temperature_sensor->temp_meas_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE
  ));
  return cluster_list;
}

static esp_zb_ep_list_t *custom_temperature_sensor_ep_create(uint8_t endpoint_id, esp_zb_temperature_sensor_cfg_t *temperature_sensor) {
  esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create();
  esp_zb_endpoint_config_t endpoint_config = {
    .endpoint = endpoint_id, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID, .app_device_version = 0
  };
  esp_zb_ep_list_add_ep(ep_list, custom_temperature_sensor_clusters_create(temperature_sensor), endpoint_config);
  return ep_list;
}

static void esp_zb_task(void *pvParameters) {
  msu_ConnectionSem = xSemaphoreCreateBinary();
  if(msu_ConnectionSem == NULL) {
    while(1) {
      Serial0.println("NULL Sem");
    }
  }

  esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG();
  //esp_zb_sleep_enable(true);
  //ESP_ERROR_CHECK_WITHOUT_ABORT(esp_zb_sleep_set_threshold(20));
  esp_zb_init(&zb_nwk_cfg);

  /* Create customized temperature sensor endpoint */
  esp_zb_temperature_sensor_cfg_t sensor_cfg = ESP_ZB_DEFAULT_TEMPERATURE_SENSOR_CONFIG();
  /* Set (Min|Max)MeasuredValure */
  //sensor_cfg.temp_meas_cfg.min_value = zb_temperature_to_s16(ESP_TEMP_SENSOR_MIN_VALUE);
  //sensor_cfg.temp_meas_cfg.max_value = zb_temperature_to_s16(ESP_TEMP_SENSOR_MAX_VALUE);
  sensor_cfg.temp_meas_cfg.min_value = zb_temperature_to_s16(POOL_TEMP_SENSOR_MIN_VALUE);
  sensor_cfg.temp_meas_cfg.max_value = zb_temperature_to_s16(POOL_TEMP_SENSOR_MAX_VALUE);
  esp_zb_ep_list_t *esp_zb_sensor_ep = custom_temperature_sensor_ep_create(HA_ESP_SENSOR_ENDPOINT, &sensor_cfg);
  /* Register the device */
  esp_zb_device_register(esp_zb_sensor_ep);

  /* Config the reporting info  */
  esp_zb_zcl_reporting_info_t reporting_info = {
    .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV,
    .ep = HA_ESP_SENSOR_ENDPOINT,
    .cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT,
    .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
    .attr_id = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
    .u =
      {
        .send_info =
          {
            .min_interval = 1,
            .max_interval = 0,
            .delta =
              {
                .u16 = 100,
              },
            .def_min_interval = 1,
            .def_max_interval = 0,
          },
      },
    .dst =
      {
        .profile_id = ESP_ZB_AF_HA_PROFILE_ID,
      },
    .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC,
  };
  esp_zb_zcl_update_reporting_info(&reporting_info);
  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();
}

/********************* GPIO functions **************************/
static QueueHandle_t gpio_evt_queue = NULL;

static void IRAM_ATTR gpio_isr_handler(void *arg) {
  xQueueSendFromISR(gpio_evt_queue, (switch_func_pair_t *)arg, NULL);
}

static void switch_gpios_intr_enabled(bool enabled) {
  for (int i = 0; i < PAIR_SIZE(button_func_pair); ++i) {
    if (enabled) {
      enableInterrupt((button_func_pair[i]).pin);
    } else {
      disableInterrupt((button_func_pair[i]).pin);
    }
  }
}

// Create a new instance of the oneWire class to communicate with any OneWire device:
OneWire msu_oneWire(ONE_WIRE_BUS);

// Pass the oneWire reference to DallasTemperature library:
DallasTemperature msu_sensors(&msu_oneWire);


/************************ Temp sensor *****************************/
static void temp_sensor_value_update(void *arg) {
  msu_sensors.begin();

  uint8_t trials = 0;

  for (;;) {
    msu_sensors.requestTemperatures(); 
    float msu_temperatureC = msu_sensors.getTempCByIndex(0);
    Serial0.print(msu_temperatureC);
    Serial0.println("ÂşC");

    esp_app_temp_sensor_handler(msu_temperatureC);

    Serial0.println("Direct sleep now");
    Serial0.flush(); 
    esp_deep_sleep_start();
  //Serial.println("This will never be printed");
    
    vTaskDelay(pdMS_TO_TICKS(100000));
  }
}

//#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
//#define TIME_TO_SLEEP  30        /* Time ESP32 will go to sleep (in seconds) */

//RTC_DATA_ATTR int bootCount = 0;

/********************* Define functions **************************/
static void s_oneshot_timer_callback(void* arg)
{
    /* Enter deep sleep */
    Serial0.println("Enter deep sleep");
    Serial0.flush();
    gettimeofday(&s_sleep_enter_time, NULL);
    esp_deep_sleep_start();
}


static void zb_deep_sleep_init(void)
{
    /* Within this function, we print the reason for the wake-up and configure the method of waking up from deep sleep.
    This example provides support for two wake-up sources from deep sleep: RTC timer and GPIO. */

    /* The one-shot timer will start when the device transitions to the CHILD state for the first time.
    After a 5-second delay, the device will enter deep sleep. */

    const esp_timer_create_args_t s_oneshot_timer_args = {
            .callback = &s_oneshot_timer_callback,
            .name = "one-shot"
    };

    ESP_ERROR_CHECK(esp_timer_create(&s_oneshot_timer_args, &s_oneshot_timer));

    // Print the wake-up reason:
    struct timeval now;
    gettimeofday(&now, NULL);
    int sleep_time_ms = (now.tv_sec - s_sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - s_sleep_enter_time.tv_usec) / 1000;
    esp_sleep_wakeup_cause_t wake_up_cause = esp_sleep_get_wakeup_cause();
    switch (wake_up_cause) {
    case ESP_SLEEP_WAKEUP_TIMER: {
        ESP_LOGI(TAG, "Wake up from timer. Time spent in deep sleep and boot: %dms", sleep_time_ms);
        break;
    }
    case ESP_SLEEP_WAKEUP_EXT1: {
        ESP_LOGI(TAG, "Wake up from GPIO. Time spent in deep sleep and boot: %dms", sleep_time_ms);
        break;
    }
    case ESP_SLEEP_WAKEUP_UNDEFINED:
    default:
        ESP_LOGI(TAG, "Not a deep sleep reset");
        break;
    }

    /* Set the methods of how to wake up: */
    /* 1. RTC timer waking-up */
    //const int wakeup_time_sec = 14400-4; // Removed some seconds to compensate each startup
    const int wakeup_time_sec = 300-4; // Removed some seconds to compensate each startup
    ESP_LOGI(TAG, "Enabling timer wakeup, %ds\n", wakeup_time_sec);
    ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(((uint64_t)wakeup_time_sec) * 1000000));

}

/********************* Arduino functions **************************/
void setup() {

  //Serial.begin(115200);
  Serial0.begin(115200);

  // Enable external Antenna
  // power the RF switch with GPIO 3 HI
  // Switch to ext antenna with GPIO 14 HI
  pinMode(3,OUTPUT);
  digitalWrite(3,HIGH);
  pinMode(14,OUTPUT);
  digitalWrite(14,HIGH);

  //Increment boot number and print it every reboot
  //++bootCount;
  //Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  //print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 seconds
  */
  //esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  //Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
  //" Seconds");

  // 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 button switch
  for (int i = 0; i < PAIR_SIZE(button_func_pair); i++) {
    pinMode(button_func_pair[i].pin, INPUT_PULLUP);
    /* create a queue to handle gpio event from isr */
    gpio_evt_queue = xQueueCreate(10, sizeof(switch_func_pair_t));
    if (gpio_evt_queue == 0) {
      Serial0.println("Queue was not created and must not be used");
      while (1);
    }
    attachInterruptArg(button_func_pair[i].pin, gpio_isr_handler, (void *)(button_func_pair + i), FALLING);
  }

  // Report previous wake up cause & Programming next wake up on timer
  zb_deep_sleep_init();

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

void loop() {
  // Handle button switch in loop()
  uint8_t pin = 0;
  switch_func_pair_t button_func_pair;
  static switch_state_t switch_state = SWITCH_IDLE;
  bool evt_flag = false;
  float temperature;

  /* check if there is any queue received, if yes read out the button_func_pair */
  if (xQueueReceive(gpio_evt_queue, &button_func_pair, portMAX_DELAY)) {
    pin = button_func_pair.pin;
    switch_gpios_intr_enabled(false);
    evt_flag = true;
  }
  while (evt_flag) {
    bool value = digitalRead(pin);
    switch (switch_state) {
      case SWITCH_IDLE:           switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE; break;
      case SWITCH_PRESS_DETECTED: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED; break;
      case SWITCH_RELEASE_DETECTED:
        switch_state = SWITCH_IDLE;
        /* callback to button_handler */
        (*esp_zb_buttons_handler)(&button_func_pair);
        break;
      default: break;
    }
    if (switch_state == SWITCH_IDLE) {
      switch_gpios_intr_enabled(true);
      evt_flag = false;
      break;
    }
    delay(10);
  }
}

Basically:

  • it uses One wire Dallas temperature sensor
  • Goes to deep sleep between 2 measurment sending
  • init and send using zigbee stack
  • traces using Serial0

Thanks for any help

Michel

Hi there,
So I get different errors, depending on which BSP I select , So that tells me it matters which is used with these other libraries.
Can you provide the first 3 lines of the compiler output(may need to be in Verbose mode in the preferans) and the last 10-12 before the upload part. This will help diagnose what environment you have set, You I’m sure set the end Device and the correct partition size.
Next:
I would look to hardware connection next. Can you post a picture of this setup?
The looping sounds to me like a strapping pin is in the incorrect state after reset.
I would double check that as well.
HTH
GL :slight_smile: PJ :v:

1 Like

Hello,

Thank you, for these concern sharing.
I will focus on the issue reproduction w/o the temperature sensor stuff.
That will remove one pullup on GPIO connected to the sensor. A bit shorter code, less GPIO manipulation at runtime, and dramatically simpler HW (USB and battery connection to the pad below the Xiao Seeed studio module).

If that would be important, would you have also advice to make sure the Arduino IDE env is clean ? (I mean, w/o using a brand new PC…)

Thx

Michel

Hi there,
So sounds like you have a plan, and I would agree on having a clean dev environment.
I definitely see better outcomes if the follow basic rules are followed.

  • Arduino IDE should be installed and the projects folder should be off of the root Drive C: or D: (file paths are short and optimal)

  • Remove any unused Libraries.

For example If you had ArduinoBLE LIB loaded and you try to use the ESP32xx With any BLE it will compile but not work ofcourse. (removing it allows the correct linkage and the program runs) :v:

  • Keep the libraries folder clean, no strange folders or files. (maybe a lvgl.conf) or something is ok. LLOL.

  • Cables:

If I had a dollar for every time I’ve seen that. Be Sure your cables are the correct ones. Real USB-c cable for example.

  • Compile an Empty Sketch with out any errors. (you would be surprised?? I know)

Always use a verbose compiler output . (the error messages will help you)
So those would be some of my recommends and don’t always jump to the latest Updated IDE version unless it’s a must and you test it’s behavior against a known good project/program

HTH
GL :slight_smile: PJ :v:

Hello,

In this investigation of XIAO-ESP32C6 software looping when USB device not plugged, I believe I made serious progress, possibly having the solution, but not sure if reliable.

As planned, I simplified the code by removing reading of temperature on external dallas device. Less libraries, less pin used, just a benefit for investigation…

I fail including picture in this message. But connections are really simple:

  • 3.7V 3800mAh Battery connected to pads below the module
  • CH340 UART to USB convertor RX connected to module TX(D6) pin
  • USB C cable connected for flashing from Arduino IDE
  • External Antenna connected to dedicated connector on the module.

The problem clearly follows activation of external Antenna.
According to module schematics and confirmed by Tips in https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/, this sequence I believe is correct (and by the way, RF range is increased as expected):

  // Enable external Antenna
  // power the RF switch with GPIO 3 HI
  // Switch to ext antenna with GPIO 14 HI
  pinMode(3,OUTPUT);
  digitalWrite(3,HIGH);
  pinMode(14,OUTPUT);
  digitalWrite(14,HIGH);

Saying this, I do not catch why I have to put it in a very late part of the software execution. So late that I wonder if the RF switch ramp-up is fully done when used. And is it working by chance in that place or there is an real rule to follow.

Below is the code that looks accepting power cycle and reset.
The sequence is commented out in 3 places, and active in PLACE #4, just before calling esp_zb_start().

What’s your opinion ?

// Copyright 2024 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.

static const char *TAG = "ESP_ZB_DEEP_SLEEP";

static int isConnected = 0;

/**
 * @brief This example demonstrates simple Zigbee temperature sensor.
 *
 * The example demonstrates how to use ESP Zigbee stack to create a end device temperature sensor.
 * The temperature sensor 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"

static RTC_DATA_ATTR struct timeval s_sleep_enter_time;
static esp_timer_handle_t s_oneshot_timer;


/* Switch configuration */
#define GPIO_INPUT_IO_TOGGLE_SWITCH GPIO_NUM_9
#define PAIR_SIZE(TYPE_STR_PAIR)    (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0]))

typedef enum {
  SWITCH_ON_CONTROL,
  SWITCH_OFF_CONTROL,
  SWITCH_ONOFF_TOGGLE_CONTROL,
  SWITCH_LEVEL_UP_CONTROL,
  SWITCH_LEVEL_DOWN_CONTROL,
  SWITCH_LEVEL_CYCLE_CONTROL,
  SWITCH_COLOR_CONTROL,
} switch_func_t;

typedef struct {
  uint8_t pin;
  switch_func_t func;
} switch_func_pair_t;

typedef enum {
  SWITCH_IDLE,
  SWITCH_PRESS_ARMED,
  SWITCH_PRESS_DETECTED,
  SWITCH_PRESSED,
  SWITCH_RELEASE_DETECTED,
} switch_state_t;

static switch_func_pair_t button_func_pair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}};

/* 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               4000                                 /* 3000 millisecond */
#define HA_ESP_SENSOR_ENDPOINT      10                                   /* esp temperature sensor device endpoint, used for temperature measurement */
#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */

/* Temperature sensor configuration */
#define ESP_TEMP_SENSOR_UPDATE_INTERVAL (1)  /* Local sensor update interval (second) */
#define POOL_TEMP_SENSOR_MIN_VALUE (-30)
#define POOL_TEMP_SENSOR_MAX_VALUE (55)

/* Attribute values in ZCL string format
 * The string should be started with the length of its own.
 */
#define MANUFACTURER_NAME \
  "\x0B"                  \
  "ESPRESSIF_------"
#define MODEL_IDENTIFIER "\x09" CONFIG_IDF_TARGET "_------"

/********************* Zigbee functions **************************/
static int16_t zb_temperature_to_s16(float temp) {
  return (int16_t)(temp * 100);
}

static void esp_zb_buttons_handler(switch_func_pair_t *button_func_pair) {
  if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) {
    /* Send report attributes command */
    esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
    report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
    report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
    report_attr_cmd.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
    report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
    report_attr_cmd.zcl_basic_cmd.src_endpoint = HA_ESP_SENSOR_ENDPOINT;

    esp_zb_lock_acquire(portMAX_DELAY);
    esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
    esp_zb_lock_release();
    Serial0.println("Send 'report attributes' command");
  }
}

static void esp_app_temp_sensor_handler(float temperature) {
  int16_t measured_value = zb_temperature_to_s16(temperature);
  Serial0.println("Updating temperature sensor value...");
  Serial0.println(measured_value);
  /* Update temperature sensor measured value */
  esp_zb_lock_acquire(portMAX_DELAY);
  esp_zb_zcl_set_attribute_val(
    HA_ESP_SENSOR_ENDPOINT, ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, &measured_value,
    false
  );
  esp_zb_lock_release();

  Serial0.println("Report temp sensor reading");
  esp_zb_zcl_report_attr_cmd_t cmd_req2;
  cmd_req2.zcl_basic_cmd.dst_endpoint = 1; // HA_ESP_LIGHT_ENDPOINT;
  cmd_req2.zcl_basic_cmd.src_endpoint = HA_ESP_SENSOR_ENDPOINT;
  cmd_req2.zcl_basic_cmd.dst_addr_u.addr_short = 0x0000;
  cmd_req2.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
  cmd_req2.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
  cmd_req2.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
  cmd_req2.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
  esp_zb_lock_acquire(portMAX_DELAY);
  ESP_ERROR_CHECK_WITHOUT_ABORT(esp_zb_zcl_report_attr_cmd_req(&cmd_req2));
  esp_zb_lock_release();
  Serial0.println("Reports sent");
}

static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) {
  ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask));
}

static void zb_deep_sleep_start(void)
{
    /* Start the one-shot timer */
    const int before_deep_sleep_time_sec = 5;
    ESP_LOGI(TAG, "Start one-shot timer for %ds to enter the deep sleep", before_deep_sleep_time_sec);
    ESP_ERROR_CHECK(esp_timer_start_once(s_oneshot_timer, before_deep_sleep_time_sec * 1000000));
}

uint8_t stackInitTrial = 0;

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:
      Serial0.println("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) {
        Serial0.println("Start network steering");

        // Start Temperature sensor reading task. 
        xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 4, NULL);

        if (esp_zb_bdb_is_factory_new()) {
          Serial0.println("Start Net Steering - fact new");
          esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
        } else {
          Serial0.println("deep sleep start - fact NOT new");
          zb_deep_sleep_start(); // starts 5s timer before sleep
          Serial0.println("Device rebooted");
          isConnected = 1;
        }
      } else {
        /* commissioning failed */
        Serial0.println("Init stak failed");
        Serial0.print("Failed to initialize Zigbee stack. Status:");
        Serial0.println(esp_err_to_name(err_status));
        if(++stackInitTrial > 5) {
          esp_deep_sleep_start(); // Will try again later
        } else {
          esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
        }
      }
      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()
        //);
        Serial0.println("Joined");
        isConnected = 1;
      } else {
        Serial0.println("Fail steering");
        Serial0.print("Network steering was not successful:");
        Serial0.println(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;
    case ESP_ZB_COMMON_SIGNAL_CAN_SLEEP:
      Serial0.println("Can sleep");
      break;
    default: 
      Serial0.print("Unk signal:");
      Serial0.print(sig_type);
      Serial0.print("=");
      Serial0.println(esp_zb_zdo_signal_to_string(sig_type));
      Serial0.print(" err=");
      Serial0.println(esp_err_to_name(err_status)); 
      break;
  }
}

static esp_zb_cluster_list_t *custom_temperature_sensor_clusters_create(esp_zb_temperature_sensor_cfg_t *temperature_sensor) {
  esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();
  esp_zb_attribute_list_t *basic_cluster = esp_zb_basic_cluster_create(&(temperature_sensor->basic_cfg));
  ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)MANUFACTURER_NAME));
  ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)MODEL_IDENTIFIER));
  ESP_ERROR_CHECK(esp_zb_cluster_list_add_basic_cluster(cluster_list, basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE));
  ESP_ERROR_CHECK(
    esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(&(temperature_sensor->identify_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE)
  );
  ESP_ERROR_CHECK(
    esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE)
  );
  ESP_ERROR_CHECK(esp_zb_cluster_list_add_temperature_meas_cluster(
    cluster_list, esp_zb_temperature_meas_cluster_create(&(temperature_sensor->temp_meas_cfg)), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE
  ));
  return cluster_list;
}

static esp_zb_ep_list_t *custom_temperature_sensor_ep_create(uint8_t endpoint_id, esp_zb_temperature_sensor_cfg_t *temperature_sensor) {
  esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create();
  esp_zb_endpoint_config_t endpoint_config = {
    .endpoint = endpoint_id, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_TEMPERATURE_SENSOR_DEVICE_ID, .app_device_version = 0
  };
  esp_zb_ep_list_add_ep(ep_list, custom_temperature_sensor_clusters_create(temperature_sensor), endpoint_config);
  return ep_list;
}

static void esp_zb_task(void *pvParameters) {

#if 0
  // PLACE #3
  // Enable external Antenna
  // power the RF switch with GPIO 3 HI
  // Switch to ext antenna with GPIO 14 HI
  pinMode(3,OUTPUT);
  digitalWrite(3,HIGH);
  pinMode(14,OUTPUT);
  digitalWrite(14,HIGH);
#endif

  esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG();
  esp_zb_init(&zb_nwk_cfg);

  /* Create customized temperature sensor endpoint */
  esp_zb_temperature_sensor_cfg_t sensor_cfg = ESP_ZB_DEFAULT_TEMPERATURE_SENSOR_CONFIG();
  /* Set (Min|Max)MeasuredValure */
  sensor_cfg.temp_meas_cfg.min_value = zb_temperature_to_s16(POOL_TEMP_SENSOR_MIN_VALUE);
  sensor_cfg.temp_meas_cfg.max_value = zb_temperature_to_s16(POOL_TEMP_SENSOR_MAX_VALUE);
  esp_zb_ep_list_t *esp_zb_sensor_ep = custom_temperature_sensor_ep_create(HA_ESP_SENSOR_ENDPOINT, &sensor_cfg);
  /* Register the device */
  esp_zb_device_register(esp_zb_sensor_ep);

  /* Config the reporting info  */
  esp_zb_zcl_reporting_info_t reporting_info = {
    .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV,
    .ep = HA_ESP_SENSOR_ENDPOINT,
    .cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT,
    .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
    .attr_id = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
    .u =
      {
        .send_info =
          {
            .min_interval = 1,
            .max_interval = 0,
            .delta =
              {
                .u16 = 100,
              },
            .def_min_interval = 1,
            .def_max_interval = 0,
          },
      },
    .dst =
      {
        .profile_id = ESP_ZB_AF_HA_PROFILE_ID,
      },
    .manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC,
  };
  esp_zb_zcl_update_reporting_info(&reporting_info);
  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

#if 1
  // PLACE #4
  // Enable external Antenna
  // power the RF switch with GPIO 3 HI
  // Switch to ext antenna with GPIO 14 HI
  pinMode(3,OUTPUT);
  digitalWrite(3,HIGH);
  pinMode(14,OUTPUT);
  digitalWrite(14,HIGH);
#endif

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

/********************* GPIO functions **************************/
static QueueHandle_t gpio_evt_queue = NULL;

static void IRAM_ATTR gpio_isr_handler(void *arg) {
  xQueueSendFromISR(gpio_evt_queue, (switch_func_pair_t *)arg, NULL);
}

static void switch_gpios_intr_enabled(bool enabled) {
  for (int i = 0; i < PAIR_SIZE(button_func_pair); ++i) {
    if (enabled) {
      enableInterrupt((button_func_pair[i]).pin);
    } else {
      disableInterrupt((button_func_pair[i]).pin);
    }
  }
}


/************************ Temp sensor *****************************/
static void temp_sensor_value_update(void *arg) {
  for (;;) {
    if (isConnected) {
      float msu_temperatureC = 15.5;
      Serial0.print(msu_temperatureC);
      Serial0.println("ÂşC");

      esp_app_temp_sensor_handler(msu_temperatureC);

      Serial0.println("Direct sleep now");
      Serial0.flush(); 
      esp_deep_sleep_start();
      //Serial.println("This will never be printed");
    
      vTaskDelay(pdMS_TO_TICKS(100000));
    } else {
      vTaskDelay(pdMS_TO_TICKS(1000));
    }
  }
}

//#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
//#define TIME_TO_SLEEP  30        /* Time ESP32 will go to sleep (in seconds) */

//RTC_DATA_ATTR int bootCount = 0;

/********************* Define functions **************************/
static void s_oneshot_timer_callback(void* arg)
{
    /* Enter deep sleep */
    Serial0.println("Enter deep sleep");
    Serial0.flush();
    gettimeofday(&s_sleep_enter_time, NULL);
    esp_deep_sleep_start();
}


static void zb_deep_sleep_init(void)
{
    /* Within this function, we print the reason for the wake-up and configure the method of waking up from deep sleep.
    This example provides support for two wake-up sources from deep sleep: RTC timer and GPIO. */

    /* The one-shot timer will start when the device transitions to the CHILD state for the first time.
    After a 5-second delay, the device will enter deep sleep. */

    const esp_timer_create_args_t s_oneshot_timer_args = {
            .callback = &s_oneshot_timer_callback,
            .name = "one-shot"
    };

    ESP_ERROR_CHECK(esp_timer_create(&s_oneshot_timer_args, &s_oneshot_timer));

    // Print the wake-up reason:
    struct timeval now;
    gettimeofday(&now, NULL);
    int sleep_time_ms = (now.tv_sec - s_sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - s_sleep_enter_time.tv_usec) / 1000;
    esp_sleep_wakeup_cause_t wake_up_cause = esp_sleep_get_wakeup_cause();
    switch (wake_up_cause) {
    case ESP_SLEEP_WAKEUP_TIMER: {
        Serial0.println("Wake up from time");
//        ESP_LOGI(TAG, "Wake up from timer. Time spent in deep sleep and boot: %dms", sleep_time_ms);
        break;
    }
    case ESP_SLEEP_WAKEUP_EXT1: {
        Serial0.println("Wake up from GPIO");
//        ESP_LOGI(TAG, "Wake up from GPIO. Time spent in deep sleep and boot: %dms", sleep_time_ms);
        break;
    }
    case ESP_SLEEP_WAKEUP_UNDEFINED:
    default:
        Serial0.println("Wake up from time");
//        ESP_LOGI(TAG, "Not a deep sleep reset");
        break;
    }

    /* Set the methods of how to wake up: */
    /* 1. RTC timer waking-up */
    //const int wakeup_time_sec = 14400-4; // Removed some seconds to compensate each startup
    const int wakeup_time_sec = 300-4; // Removed some seconds to compensate each startup
    ESP_LOGI(TAG, "Enabling timer wakeup, %ds\n", wakeup_time_sec);
    ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(((uint64_t)wakeup_time_sec) * 1000000));

}

/********************* Arduino functions **************************/
void setup() {

  //Serial.begin(115200);
  Serial0.begin(115200);

#if 0
  // PLACE #1
  // Enable external Antenna
  // power the RF switch with GPIO 3 HI
  // Switch to ext antenna with GPIO 14 HI
  pinMode(3,OUTPUT);
  digitalWrite(3,HIGH);
  pinMode(14,OUTPUT);
  digitalWrite(14,HIGH);
#endif

  // 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 button switch
  for (int i = 0; i < PAIR_SIZE(button_func_pair); i++) {
    pinMode(button_func_pair[i].pin, INPUT_PULLUP);
    /* create a queue to handle gpio event from isr */
    gpio_evt_queue = xQueueCreate(10, sizeof(switch_func_pair_t));
    if (gpio_evt_queue == 0) {
      Serial0.println("Queue was not created and must not be used");
      while (1);
    }
    attachInterruptArg(button_func_pair[i].pin, gpio_isr_handler, (void *)(button_func_pair + i), FALLING);
  }

  // Report previous wake up cause & Programming next wake up on timer
  zb_deep_sleep_init();

#if 0
  // PLACE #2
  // Enable external Antenna
  // power the RF switch with GPIO 3 HI
  // Switch to ext antenna with GPIO 14 HI
  pinMode(3,OUTPUT);
  digitalWrite(3,HIGH);
  pinMode(14,OUTPUT);
  digitalWrite(14,HIGH);
#endif
  // Start Zigbee task
  xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL);
}

void loop() {
  // Handle button switch in loop()
  uint8_t pin = 0;
  switch_func_pair_t button_func_pair;
  static switch_state_t switch_state = SWITCH_IDLE;
  bool evt_flag = false;
  float temperature;

  /* check if there is any queue received, if yes read out the button_func_pair */
  if (xQueueReceive(gpio_evt_queue, &button_func_pair, portMAX_DELAY)) {
    pin = button_func_pair.pin;
    switch_gpios_intr_enabled(false);
    evt_flag = true;
  }
  while (evt_flag) {
    bool value = digitalRead(pin);
    switch (switch_state) {
      case SWITCH_IDLE:           switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE; break;
      case SWITCH_PRESS_DETECTED: switch_state = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED; break;
      case SWITCH_RELEASE_DETECTED:
        switch_state = SWITCH_IDLE;
        /* callback to button_handler */
        (*esp_zb_buttons_handler)(&button_func_pair);
        break;
      default: break;
    }
    if (switch_state == SWITCH_IDLE) {
      switch_gpios_intr_enabled(true);
      evt_flag = false;
      break;
    }
    delay(10);
  }
}

#if 0
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial0.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial0.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial0.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial0.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial0.println("Wakeup caused by ULP program"); break;
    default : Serial0.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

#endif
1 Like

Hi there,
So which external antenna Are you using? Can you remove the Antenna and remove any code that switches the connection away from the built in one? and try again? I believe it’s one of the problems.
HTH
LMK
GL :slight_smile: PJ :v:

Hi,

I am not sure to understand the question…
I am using a patch antenna connected by SMT to the Seed Studio Xiao esp32-C6 module.
Module and connector are visble on this https://files.seeedstudio.com/wiki/SeeedStudio-XIAO-ESP32C6/img/xiaoc6.jpg.

Schematics of the module sounds to be there : XIAO ESP32 C6.pdf (seeedstudio.com)

On page 5/5 of the PDF it confirms RF switch U5 is driven by GPIO 3 and 14. Both HIGH means using the RF signal from SMT. Otherwise, use the patch Antenna on the module.

From code perspective, may be I was not clear.
Deactivating code (using #if 0) for these pins setting in the 4 places I tried (you may seek for “PLACE #” in the code), so using the small antenna on the module ==> All works fine.
Activating external Antenna in Place #1, #2 or #3, I have the initial problem that if I unplug USB then reset or power cycle, the module reset in loop.
Activating extenal Antenna in Place #4 gives the expected result, it works.
What is not clear is why place #3 for instance creates the issue. And if Place #4 is reliable.

Thank you for the concern

Michel

From code perspective, I confirm that if I do not configure these GPIO

Hi there,
OK I understand NOW, LOL I was confused it was the other way around :face_with_peeking_eye:
So onboard Chip antenna is working, NO Loop on Reset or USB .
When you try and use the external Antenna then it loops.
Soon as I get a chance to test further I will.
Perhaps Seeed Support could comment on the Zigbee and the effect if any an External antenna may have on it?
HTH
GL :slight_smile: PJ :v:

Hi PJ and Seed support if by chance they see this.

To be more precise:
Activating the external Antenna (by GPIOs 3 & 14) just before calling esp_zb_start(), all is fine for my usage.
Not using GPIOs 3&14, also all is okay from runtime perspective, but of course on board antenna has lower range.

Problem occurs if activating external Antenna earlier in the code. This is puzzling.

Description of the problem is the board must remains connected to USB. Otherwise, if USB is not connected, only wakeup from timer works fine. Reset or power OFF/ON put module in a loop. The loop needs to replug USB to stop.

Hi there,
OK, Great work describing this wacky :crazy_face: behavior for sure. I’m already leery of the whole switchable RF front end on this thing… Especially since there is NO , Clearly Specified External Antenna that is appropriate for this device. (no SKU#) I don’t like it’s a one size fits all situation.
YUCK, :stuck_out_tongue_closed_eyes: IMO
Where’s the “beef” Test spec’s and test results of range tests with and without Ext. Antenna ? feels like a Gimmick again.
I have several Zigbee devices connected to my HomeSeer HAS, looking forward to having the ZIgbee stuff work like it should. :+1:
HTH
GL :slight_smile: PJ :v:

Almost sounds like the SWR for antenna is wrong and the reflected power is blowing up the zigbee initialization code? super freaky :skull_and_crossbones:

Hi,
We have noticed the issue you reported in this post. Our engineers are testing and investigating into it. When they have an answer, I will update here with you.

1 Like

Hi, I checked the schematic and the switching of the internal and external antennas mainly involves the level switching of GPIO3 and GPIO14, and I wasn’t able to find any relevant information about how they would affect Zigbee inside the chip’s manual. But I noticed that the Wiki example program is already an outdated version, Espressif updated it with a new example program:

I remember a long time ago, using their unfinished sample program would also keep getting constant reboots, so if you have time, try this new program to see if it solves your problem, and of course, we’ll be scheduling a validation of this new program and then updating the Wiki, thanks for the feedback.

1 Like

My money :moneybag: is on @Citric for the WIN! …
Awesome!
:v:
GL :slight_smile: PJ :+1: