Need help structuring custom device, getting Load Access Fault Error

97cweb
Posts: 1
Joined: Wed Sep 11, 2024 2:13 pm

Need help structuring custom device, getting Load Access Fault Error

Postby 97cweb » Wed Sep 11, 2024 2:16 pm

Good morning all
I am trying to make my own custom device using an ESP32-C6 with zigbee. I cannot find any good documentation on how to make a custom device, and not even a good description of endpoint vs cluster, vs attribute lists.

I have posted my code below, the 2 functions that are bad are esp_zb_task and zb_attribute_handler

When I get this working, I will write up more info so others don't have to fight it as badly as I am

Thank you

Code: Select all

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

#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 the model and manufacturer
#define DEVICE_MODEL        "\x14""Beeton Train Decoder"   // 20 characters (14 in hex is 20 in decimal)
#define VERSION_NUMBER             "\x06""0.0.01"
#define DEVICE_MANUFACTURER "\x14""YottaRock Industries"  // 20 characters (14 in hex is 20 in decimal)

#define ZCL_BASIC_POWER_SOURCE 4

// Custom endpoint definitions
#define MOTOR_CONTROL_ENDPOINT    1
#define OUTPUT_CONTROL_ENDPOINT    2
#define IO_CONTROL_ENDPOINT        3
#define SOUND_CONTROL_ENDPOINT     4

// Motion control attributes
int motor_speed = 0;    // Motor speed range from -1024 to 1023
bool motor_direction = true;  // True: forward, False: reverse

// Digital output attributes
bool outputs[8] = {false};  // On/Off states for 8 outputs

// IO control attributes
bool io_direction = true;  // True: output, False: input

// Sound control attributes
char sound_file[128] = "";  // Current sound file being played
bool is_playing = false;
int volume = 50;  // Volume level (0-100)

/* 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 BEETON_TRAIN_ENDPOINT 1                                          /* esp light bulb device endpoint, used to process light controlling commands */
#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) {
  log_i("Handling signals...");
  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 {
        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);
        rgbLedWrite(RGB_BUILTIN, 10, 0, 0);
        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 {
        rgbLedWrite(RGB_BUILTIN, 10, 0, 10);
        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);

    //info list
    esp_zb_attribute_list_t *esp_zb_basic_cluster = esp_zb_basic_cluster_create(NULL);
    uint8_t powerSource = ZCL_BASIC_POWER_SOURCE;
    esp_zb_cluster_update_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, &powerSource);
    esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *) DEVICE_MODEL);
    esp_zb_basic_cluster_add_attr(esp_zb_basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *) DEVICE_MANUFACTURER);

    // Motor control (Endpoint 1)
    esp_zb_attribute_list_t *motor_control = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL);
    esp_zb_attribute_list_t *motor_onoff = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ON_OFF);
    
    esp_zb_cluster_list_t *motor_cluster = esp_zb_zcl_cluster_list_create();
    esp_zb_cluster_list_add_custom_cluster( motor_cluster, motor_control, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE) ;
    esp_zb_cluster_list_add_custom_cluster(motor_cluster, motor_onoff, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // Output control (Endpoint 2)
    esp_zb_attribute_list_t *output_control_attributes = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ON_OFF);
    esp_zb_cluster_list_t *output_control_cluster = esp_zb_zcl_cluster_list_create();
    esp_zb_cluster_list_add_on_off_cluster(output_control_cluster, output_control_attributes, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // IO control (Endpoint 3)
    esp_zb_attribute_list_t *io_control_attributes = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_MULTI_VALUE);
    esp_zb_cluster_list_t *io_control_cluster = esp_zb_zcl_cluster_list_create();
    esp_zb_cluster_list_add_multistate_value_cluster(io_control_cluster, io_control_attributes, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // Sound control (Endpoint 4)
    esp_zb_attribute_list_t *sound_control_attribute = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_ON_OFF);
    esp_zb_attribute_list_t *sound_volume_attribute = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL);
    esp_zb_attribute_list_t *sound_file_attribute = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_BASIC);  // Custom attribute for file name
    
    esp_zb_cluster_list_t *sound_control_list = esp_zb_zcl_cluster_list_create();
    esp_zb_cluster_list_add_on_off_cluster(sound_control_list, sound_control_attribute, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
    esp_zb_cluster_list_add_multistate_value_cluster(sound_control_list, sound_volume_attribute, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
    esp_zb_cluster_list_add_custom_cluster(sound_control_list, sound_file_attribute, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);  // Add custom file cluster

    // Register endpoints
    esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create();

    // Motion control endpoint (1)
    esp_zb_endpoint_config_t motion_endpoint = {
        .endpoint = MOTOR_CONTROL_ENDPOINT,
        .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
        .app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
        .app_device_version = 0
    };
    esp_zb_ep_list_add_ep(ep_list, motor_cluster, motion_endpoint);

    // Output control endpoint (2)
    esp_zb_endpoint_config_t output_endpoint = {
        .endpoint = OUTPUT_CONTROL_ENDPOINT,
        .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
        .app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
        .app_device_version = 0
    };
    esp_zb_ep_list_add_ep(ep_list, output_control_cluster, output_endpoint);

    // IO control endpoint (3)
    esp_zb_endpoint_config_t io_endpoint = {
        .endpoint = IO_CONTROL_ENDPOINT,
        .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
        .app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
        .app_device_version = 0
    };
    esp_zb_ep_list_add_ep(ep_list, io_control_cluster, io_endpoint);

    // Sound control endpoint (4)
    esp_zb_endpoint_config_t sound_endpoint = {
        .endpoint = SOUND_CONTROL_ENDPOINT,
        .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
        .app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID,
        .app_device_version = 0
    };
    esp_zb_ep_list_add_ep(ep_list, sound_control_list, sound_endpoint);

    // Register and start Zigbee
    esp_zb_device_register(ep_list);


  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 connecting 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;
  uint8_t endpoint = message->info.dst_endpoint;
  uint16_t cluster_id = message->info.cluster;
  uint16_t attr_id = message->attribute.id;

  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)", endpoint, cluster_id, attr_id,
    message->attribute.data.size);

  
  switch (endpoint) {
    case MOTOR_CONTROL_ENDPOINT:
        if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL) {
            if (attr_id == ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID) {
                motor_speed = *(int *)message->attribute.data.value;
                ESP_LOGI("MOTION", "Motor speed set to %d", motor_speed);
            }
            if (attr_id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID) {
                motor_direction = *(bool *)message->attribute.data.value;
                ESP_LOGI("MOTION", "Motor direction set to %s", motor_direction ? "Forward" : "Reverse");
            }
        }
        break;

    case OUTPUT_CONTROL_ENDPOINT:
        if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
            int output_id = attr_id - ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID;
            if (output_id >= 0 && output_id < 8) {
                outputs[output_id] = *(bool *)message->attribute.data.value;
                ESP_LOGI("OUTPUT", "Output %d set to %s", output_id, outputs[output_id] ? "On" : "Off");
            }
        }
        break;

    case IO_CONTROL_ENDPOINT:
        if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
            io_direction = *(bool *)message->attribute.data.value;
            ESP_LOGI("IO", "IO direction set to %s", io_direction ? "Output" : "Input");
        }
        break;

    case SOUND_CONTROL_ENDPOINT:
        if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
            if (attr_id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID) {
                is_playing = *(bool *)message->attribute.data.value;
                ESP_LOGI("SOUND", "%s audio playback", is_playing ? "Starting" : "Stopping");
            }
        } else if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL) {
            if (attr_id == ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID) {
                volume = *(int *)message->attribute.data.value;
                ESP_LOGI("SOUND", "Volume set to %d", volume);
            }
        } else if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_BASIC && attr_id == 0x000F) {  // Custom attribute for sound file
            strcpy(sound_file, (char *)message->attribute.data.value);
            ESP_LOGI("SOUND", "Sound file set to: %s", sound_file);
        }
        break;
    }

    return ret;
}

/********************* Arduino functions **************************/
void setup() {
  // Show power light
  rgbLedWrite(RGB_BUILTIN, 0, 10, 0);

  // 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));

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

void loop() {
}


KMTsvetanov
Posts: 3
Joined: Tue Nov 26, 2024 1:49 pm

Re: Need help structuring custom device, getting Load Access Fault Error

Postby KMTsvetanov » Tue Nov 26, 2024 1:53 pm

Did you fix it?
I'm testing with esp32-h2
And i just have this code:

Code: Select all

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

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


esp_zb_init(&zb_nwk_cfg); gives me an error in the monitor

And I don't know what to do...

Code: Select all

I (474) ESP_ZIGBEE_CORE: SDK Version: v1.6.0-c8fc5f64-9c23bfd9-4f5d21f; esp32h2; 2024-11-01 07:13:22 UTC
Guru Meditation Error: Core  0 panic'ed (Load access fault). Exception was unhandled.

lbernstone
Posts: 858
Joined: Mon Jul 22, 2019 3:20 pm

Re: Need help structuring custom device, getting Load Access Fault Error

Postby lbernstone » Wed Nov 27, 2024 2:40 am

Zigbee support has improved tremendously in arduino-esp32 over the past few months. The Espressif team has put together a number of examples, along with a framework you can use as a template for your own custom endpoints.
If you wish to continue troubleshooting your issue, you will need to decode the backtrace. There are instructions to do this in Arduino and ESP-IDF. If you are using the IDF monitor, it should decode the backtrace automatically.

Who is online

Users browsing this forum: No registered users and 37 guests