[Zigbee] IAS based Endpoints do not call response callback handler

Author: SLAZ666Created Sep 1, 2026Updated Sep 11, 2026
LabelsIDE: Arduino IDEArea: Zigbee

Board

ESP32-C6

Device Description

Plain Seed Studio XIAO ESP32-C6

Hardware Configuration

Hall sensor switch on pin D1

Version

v3.3.11

Type

Bug

IDE Name

Arduino IDE

Operating System

Linux

Flash frequency

160MHz

PSRAM enabled

no

Upload speed

921600

Description

IAS based Endpoints like ZigbeeContactSwitch or ZigbeeDoorWindowHandle do not call the response callback, which is necessary to implement a proper battery powered device like in the example of Zigbee_Temp_Hum_Sensor_Sleepy

In the minimal example attached the onGlobalResponse callback gets never called even so the state of the contact switch is successfully transferred to the controller. Also using only the onResponse callback it is not working.

The controller is used with Zigbee2mqtt 2.7.2

Sketch

cpp
// 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.

/**
 * @brief This example demonstrates Zigbee contact switch (IAS Zone).
 *
 * The example demonstrates how to use Zigbee library to create a end device contact switch.
 * The contact switch is a Zigbee end device, which is reporting data to the Zigbee network.
 *
 * 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.
 *
 * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
 */

#include <Arduino.h>
#ifndef ZIGBEE_MODE_ED
#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
#endif

#include "Zigbee.h"
#include <Preferences.h>

#define USE_GLOBAL_ON_RESPONSE_CALLBACK 1  // Set to 0 to use local callback specified directly for the endpoint.

/* Zigbee contact sensor configuration */
#define CONTACT_SWITCH_ENDPOINT_NUMBER 1
uint8_t button = BOOT_PIN;
uint8_t sensor_pin = D1;

ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER);

/* Preferences for storing ENROLLED flag to persist across reboots */
Preferences preferences;

#if USE_GLOBAL_ON_RESPONSE_CALLBACK
void onGlobalResponse(zb_cmd_type_t command, esp_zb_zcl_status_t status, uint8_t endpoint, uint16_t cluster) {
  Serial.printf("Global response command: %d, status: %s, endpoint: %u, cluster: 0x%04x\r\n", command, esp_zb_zcl_status_to_name(status), endpoint, cluster);
}
#else
void onResponse(zb_cmd_type_t command, esp_zb_zcl_status_t status) {
  Serial.printf("Response command: %d, status: %s\r\n", command, esp_zb_zcl_status_to_name(status));
}
#endif

void setup() {
  Serial.begin(115200);

  preferences.begin("Zigbee", false);               // Save ENROLLED flag in flash so it persists across reboots
  bool enrolled = preferences.getBool("ENROLLED");  // Get ENROLLED flag from preferences
  preferences.end();

  // Init button + switch
  pinMode(button, INPUT_PULLUP);
  pinMode(sensor_pin, INPUT_PULLUP);

  // Optional: set Zigbee device name and model
  zbContactSwitch.setManufacturerAndModel("Espressif", "ZigbeeContactSwitch");

#if USE_GLOBAL_ON_RESPONSE_CALLBACK
  // Global callback for all endpoints with more params to determine the endpoint and cluster in the callback function.
  Zigbee.onGlobalDefaultResponse(onGlobalResponse);
#else
  // Callback specified for endpoint
  zbContactSwitch.onDefaultResponse(onResponse);
#endif

  // Add endpoint to Zigbee Core
  Zigbee.addEndpoint(&zbContactSwitch);

  Serial.println("Starting Zigbee...");
  // When all EPs are registered, start Zigbee in End Device mode
  if (!Zigbee.begin()) {
    Serial.println("Zigbee failed to start!");
    Serial.println("Rebooting...");
    ESP.restart();
  } else {
    Serial.println("Zigbee started successfully!");
  }
  Serial.println("Connecting to network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(100);
  }
  Serial.println();

  // Check if device has been enrolled before restarting - if so, restore IAS Zone enroll, otherwise request new IAS Zone enroll
  if (enrolled) {
    Serial.println("Device has been enrolled before - restoring IAS Zone enrollment");
    zbContactSwitch.restoreIASZoneEnroll();
  } else {
    Serial.println("Device is factory new - first time joining network - requesting new IAS Zone enrollment");
    zbContactSwitch.requestIASZoneEnroll();
  }

  while (!zbContactSwitch.enrolled()) {
    Serial.print(".");
    delay(100);
  }
  Serial.println();
  Serial.println("Zigbee enrolled successfully!");

  // Store ENROLLED flag only if this was a new enrollment (previous flag was false)
  // Skip writing if we just restored enrollment (flag was already true)
  if (!enrolled) {
    preferences.begin("Zigbee", false);
    preferences.putBool("ENROLLED", true);  // set ENROLLED flag to true
    preferences.end();
    Serial.println("ENROLLED flag saved to preferences");
  }
}

void loop() {
  // Checking pin for contact change
  static bool contact = false;
  if (digitalRead(sensor_pin) == HIGH && !contact) {
    // Update contact sensor value
    zbContactSwitch.setOpen();
    Serial.println("Contact open");
    contact = true;
  } else if (digitalRead(sensor_pin) == LOW && contact) {
    zbContactSwitch.setClosed();
    Serial.println("Contact close");
    contact = false;
  }

  // Checking button for factory reset
  if (digitalRead(button) == LOW) {  // Push button pressed
    // Key debounce handling
    delay(100);
    int startTime = millis();
    while (digitalRead(button) == LOW) {
      delay(50);
      if ((millis() - startTime) > 3000) {
        // If key pressed for more than 3secs, factory reset Zigbee and reboot
        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
        // Clear the ENROLLED flag from preferences
        preferences.begin("Zigbee", false);
        preferences.putBool("ENROLLED", false);  // set ENROLLED flag to false
        preferences.end();
        Serial.println("ENROLLED flag cleared from preferences");
        delay(1000);
        Zigbee.factoryReset();
      }
    }
  }
  delay(100);
}

Debug Message

plain
=========== Before Setup Start ===========
Chip Info:
------------------------------------------
  Model             : ESP32-C6
  Package           : 1
  Revision          : 0.01
  Cores             : 1
  CPU Frequency     : 160 MHz
  XTAL Frequency    : 4tures Bitfield : 0x00000052
  Embedded Flash    : No
  Embedded PSRAM    : No
  2.4GHz WiFi       : Yes
  Classic BT        : No
  BT Low Energy     : Yes
  IEEE 802.15.4     : Yes
------------------------------------------
INTERNAL Memory Info:
------------------------------------------
  Total Size        :   441388 B ( 431.0 KB)
  Free Bytes        :   408684 B ( 399.1 KB)
  Allocated Bytes   :    25648 B (  25.0 KB)
  Minimum Free Bytes:   403696 B ( 394.2 KB)
  Largest Free Block:   385012 B ( 376.0 KB)
------------------------------------------
Flash Info:
------------------------------------------
  Chip Size         :  4194304B (4 MB)
  Block Size        :    65536B (  64.0 KB)
  Sector Size       :     4096B (   4.0 KB)
  Page Size         :      256B (   0.2 KB)
  Bus Speed         : 80 MHz
  Flash Frequency   : 80 MHz (source: 80 MHz, divider: 1)
  Bus Mode          : QIO
------------------------------------------
Partitions Info:
------------------------------------------
                nvs : addr: 0x00009000, size:    20.0 KB, type: DATA, subtype: NVS
            otadata : addr: 0x0000E000, size:     8.0 KB, type: DATA, subtype: OTA
               app0 : addr: 0x00010000, size:  1280.0 KB, type:  APP, subtype: OTA_0
               app1 : addr: 0x00150000, size:  1280.0 KB, type:  APP, subtype: OTA_1
             spiffs : addr: 0x00290000, size:  1388.0 KB, type: DATA, subtype: SPIFFS
         zb_storage : addr: 0x003EB000, size:    16.0 KB, type: DATA, subtype: FAT
             zb_fct : addr: 0x003EF000, size:     4.0 KB, type: DATA, subtype: FAT
           coredump : addr: 0x003F0000, size:    64.0 KB, type: DATA, subtype: COREDUMP
------------------------------------------
Software Info:
------------------------------------------
  Compile Date/Time : Sep  1 2026 21:52:46
  Compile Host OS   : linux
  ESP-IDF Version   : v5.5.4
  Arduino Version   : 3.3.10
------------------------------------------
Board Info:
------------------------------------------
  Arduino Board     : XIAO_ESP32C6
  Arduino Variant   : XIAO_ESP32C6
  Arduino FQBN      : esp32:esp32:XIAO_ESP32C6:UploadSpeed=921600,CDCOnBoot=cdc,CPUFreq=160,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=zigbee,DebugLevel=debug,EraseFlash=all,JTAGAdapter=default,ZigbeeMode=ed
============ Before Setup End ============
[  1231][I][esp32-hal-periman.c:151] perimanSetPinBus(): Pin 12 already has type USB_DM (38) with bus 0x40812b08
[  1232][I][esp32-hal-periman.c:151] perimanSetPinBus(): Pin 13 already has type USB_DP (39) with bus 0x40812b08
[  1233][D][ZigbeeCore.cpp:127] addEndpoint(): Endpoint: 1, Device ID: 0x0402
Starting Zigbee...
[  1234][D][ZigbeeCore.cpp:175] zigbeeInit(): Initialize Zigbee stack
[  1305][D][ZigbeeCore.cpp:182] zigbeeInit(): Register all Zigbee EPs in list
[  1306][I][ZigbeeCore.cpp:190] zigbeeInit(): List of registered Zigbee EPs:
[  1307][I][ZigbeeCore.cpp:192] zigbeeInit(): Device type: IAS Zone, Endpoint: 1, Device ID: 0x0402
[  1454][I][ZigbeeCore.cpp:290] esp_zb_app_signal_handler(): Zigbee stack initialized
[  1454][D][ZigbeeCore.cpp:291] esp_zb_app_signal_handler(): Zigbee channel mask: 0x07fff800
[  1456][I][ZigbeeCore.cpp:297] esp_zb_app_signal_handler(): Device started up in  factory-reset mode
[  1457][I][ZigbeeCore.cpp:304] esp_zb_app_signal_handler(): Start network steering
Zigbee started successfully!
Connecting to network
...............................[  4515][I][ZigbeeCore.cpp:358] esp_zb_app_signal_handler(): Joined network successfully (Extended PAN ID: 5b:f6:da:79:14:b1:91:a6, PAN ID: 0x58fb, Channel:11, Short Address: 0xc757)

Device is factory new - first time joining network - requesting new IAS Zone enrollment
...[  4817][D][ZigbeeCore.cpp:778] searchBindings(): Requesting binding table for address 0xc757
[  4821][D][ZigbeeCore.cpp:586] bindingTableCb(): Binding table callback for address 0xc757 with status 0
[  4822][D][ZigbeeCore.cpp:590] bindingTableCb(): Binding table info: total 1, index 0, count 1
[  4823][D][ZigbeeCore.cpp:635] bindingTableCb(): Processing record 0: src_endp 1, dst_endp 1, cluster_id 0x0500, dst_addr_mode 3
[  4824][D][ZigbeeCore.cpp:650] bindingTableCb(): Processing final chunk of binding table, total records: 1
[  4824][D][ZigbeeCore.cpp:671] bindingTableCb(): Processing endpoint 1
[  4825][D][ZigbeeCore.cpp:717] bindingTableCb(): Processing binding record for EP 1
[  4825][D][ZigbeeCore.cpp:752] bindingTableCb(): Device bound to EP 1 -> device endpoint: 1, ieee addr: 00:12:4B:00:24:C2:AD:34
[  4826][D][ZigbeeCore.cpp:765] bindingTableCb(): Filling bounded devices finished
.....
Zigbee enrolled successfully!
ENROLLED flag saved to preferences
=========== After Setup Start ============
INTERNAL Memory Info:
------------------------------------------
  Total Size        :   441388 B ( 431.0 KB)
  Free Bytes        :   377172 B ( 368.3 KB)
  Allocated Bytes   :    56392 B (  55.1 KB)
  Minimum Free Bytes:   377064 B ( 368.2 KB)
  Largest Free Block:   360436 B ( 352.0 KB)
------------------------------------------
GPIO Info:
------------------------------------------
  GPIO : BUS_TYPE[bus/unit][chan]
  --------------------------------------  
     1 : GPIO
     3 : GPIO
     9 : GPIO
    12 : USB_DM
    13 : USB_DP
    14 : GPIO
============ After Setup End =============
Contact open
Contact close
Contact open
Contact close
Contact open

Other Steps to Reproduce

No response

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

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.