Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zigbee readManufacturer fail leads to reboot #10777

Open
1 task done
AndunHH opened this issue Dec 23, 2024 · 0 comments
Open
1 task done

Zigbee readManufacturer fail leads to reboot #10777

AndunHH opened this issue Dec 23, 2024 · 0 comments
Assignees
Labels
Area: Zigbee Issues and Feature Request about Zigbee Status: Awaiting triage Issue is waiting for triage

Comments

@AndunHH
Copy link

AndunHH commented Dec 23, 2024

Board

seeed xiao esp32-c6

Device Description

I use the Seeeduino-XIAO-Expansion-Board/

Hardware Configuration

nothing added

Version

latest master (checkout manually)

IDE Name

Arduino IDE 2 and pioarduino

Operating System

Ubuntu 2024.04

Flash frequency

80Mhz

PSRAM enabled

yes

Upload speed

921600

Description

When calling zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr) within the zigbee Switch example the manufacturer is reported.

Unfortunately, the timeout within this function leads to a rebooting device, because it is not handled, when the device is not answering.

I expect, that the function readManufacturer() returns a "n/a" or likewise, but is not resetting the controller, when no information could be obtained.

I tried to avoid the problem by checking zbSwitch.bound() before calling readManufacturer(), but this doesn't solve the problem, because bound() doesn't know, that I just unplugged the light.

Sketch

// 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 simple Zigbee light switch.
 *
 * The example demonstrates how to use Zigbee library to control a light bulb.
 * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator (Switch).
 * Button switch and Zigbee runs in separate tasks.
 *
 * 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/)
 */

#ifndef ZIGBEE_MODE_ZCZR
#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"
#endif

#include "Zigbee.h"

/* Zigbee switch configuration */
#define SWITCH_ENDPOINT_NUMBER 5

#define GPIO_INPUT_IO_TOGGLE_SWITCH BOOT_PIN
#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,
} SwitchFunction;

typedef struct {
  uint8_t pin;
  SwitchFunction func;
} SwitchData;

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

static SwitchData buttonFunctionPair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}};

ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER);

/********************* Zigbee functions **************************/
static void onZbButton(SwitchData *button_func_pair) {
  if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) {
    // Send toggle command to the light
    Serial.println("Toggling light");
    zbSwitch.lightToggle();
  }
}

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

static void IRAM_ATTR onGpioInterrupt(void *arg) {
  xQueueSendFromISR(gpio_evt_queue, (SwitchData *)arg, NULL);
}

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

/********************* Arduino functions **************************/
void setup() {
  Serial.begin(115200);

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

  //Optional to allow multiple light to bind to the switch
  zbSwitch.allowMultipleBinding(true);

  //Add endpoint to Zigbee Core
  Serial.println("Adding ZigbeeSwitch endpoint to Zigbee Core");
  Zigbee.addEndpoint(&zbSwitch);

  //Open network for 180 seconds after boot
  Zigbee.setRebootOpenNetwork(180);

  // Init button switch
  for (int i = 0; i < PAIR_SIZE(buttonFunctionPair); i++) {
    pinMode(buttonFunctionPair[i].pin, INPUT_PULLUP);
    /* create a queue to handle gpio event from isr */
    gpio_evt_queue = xQueueCreate(10, sizeof(SwitchData));
    if (gpio_evt_queue == 0) {
      Serial.println("Queue creating failed, rebooting...");
      ESP.restart();
    }
    attachInterruptArg(buttonFunctionPair[i].pin, onGpioInterrupt, (void *)(buttonFunctionPair + i), FALLING);
  }

  // When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode
  if (!Zigbee.begin(ZIGBEE_COORDINATOR)) {
    Serial.println("Zigbee failed to start!");
    Serial.println("Rebooting...");
    ESP.restart();
  }

  Serial.println("Waiting for Light to bound to the switch");
  //Wait for switch to bound to a light:
  while (!zbSwitch.bound()) {
    Serial.printf(".");
    delay(500);
  }

  // Optional: List all bound devices and read manufacturer and model name
  std::list<zb_device_params_t *> boundLights = zbSwitch.getBoundDevices();
  for (const auto &device : boundLights) {
    Serial.printf("Device on endpoint %d, short address: 0x%x\r\n", device->endpoint, device->short_addr);
    Serial.printf(
      "IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4],
      device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0]
    );
    Serial.printf("Light manufacturer: %s\r\n", zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr));
    Serial.printf("Light model: %s\r\n", zbSwitch.readModel(device->endpoint, device->short_addr, device->ieee_addr));
  }

  Serial.println();
}

void loop() {
  // Handle button switch in loop()
  uint8_t pin = 0;
  SwitchData buttonSwitch;
  static SwitchState buttonState = SWITCH_IDLE;
  bool eventFlag = false;

  /* check if there is any queue received, if yes read out the buttonSwitch */
  if (xQueueReceive(gpio_evt_queue, &buttonSwitch, 200)) {
    pin = buttonSwitch.pin;
    enableGpioInterrupt(false);
    eventFlag = true;
  }
  while (eventFlag) {
    bool value = digitalRead(pin);
    switch (buttonState) {
      case SWITCH_IDLE:           buttonState = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE; break;
      case SWITCH_PRESS_DETECTED: buttonState = (value == LOW) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED; break;
      case SWITCH_RELEASE_DETECTED:
        buttonState = SWITCH_IDLE;
        /* callback to button_handler */
        (*onZbButton)(&buttonSwitch);
        break;
      default: break;
    }
    if (buttonState == SWITCH_IDLE) {
      enableGpioInterrupt(true);
      eventFlag = false;
      break;
    }
    vTaskDelay(10 / portTICK_PERIOD_MS);
  }

  // print the bound lights every 10 seconds
  static uint32_t lastPrint = 0;
  if (millis() - lastPrint > 10000) {
    lastPrint = millis();
    zbSwitch.printBoundDevices(Serial);
        // Optional: List all bound devices and read manufacturer and model name
    std::list<zb_device_params_t *> boundLights = zbSwitch.getBoundDevices();
    for (const auto &device : boundLights) {
      Serial.printf("Light manufacturer: %s\r\n", zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr));
    }
  }
}

Debug Message

The ExceptionDecoder is unfortunately not running on my new ubuntu. here is the debugging:

Waiting for Light to bound to the switch
Device on endpoint 1, short address: 0x0
IEEE Address: 84:71:27:FF:FE:DC:28:D0
[   856][I][ZigbeeCore.cpp:326] esp_zb_app_signal_handler(): Network(0x5d24) is open for 180 seconds
[  7647][V][ZigbeeHandlers.cpp:82] zb_cmd_read_attr_resp_handler(): Read attribute response: from address(0x264) src endpoint(1) to dst endpoint(5) cluster(0x0)
[  7648][V][ZigbeeHandlers.cpp:91] zb_cmd_read_attr_resp_handler(): Read attribute response: status(134), cluster(0x0), attribute(0x4), type(0x0), value(0)
[ 10395][E][ZigbeeEP.cpp:148] readManufacturer(): Error while reading manuGuru Meditation Error: Core  0 panic'ed (Load access fault). Exception was unhandled.

Other Steps to Reproduce

In the pasted example I changed the xQueueReceive timeout in line 161 to 200 ticks to get to the end of the loop().
The really interesting part, is that I added the for loop in line 193 from the printBoundDevice function.

I'm using the latest master for arduino-esp32: commit 9eb7dc6

The behavior is independent of a factory-reset or not.

When the light is not available the readManufacturer runs into the unhandled exception.

I can reproduce this problems when
a) I disconnected the light bulb after successfull connection and toggling.
b) if the esp32c6 restarts and remembers the bound devices, but the actual reconnection to the light needs some time, but I'm already asking for a manufacturer.

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

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@AndunHH AndunHH added the Status: Awaiting triage Issue is waiting for triage label Dec 23, 2024
@P-R-O-C-H-Y P-R-O-C-H-Y self-assigned this Dec 23, 2024
@SuGlider SuGlider added the Area: Zigbee Issues and Feature Request about Zigbee label Dec 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Zigbee Issues and Feature Request about Zigbee Status: Awaiting triage Issue is waiting for triage
Projects
None yet
Development

No branches or pull requests

3 participants