【ESP BLE MESH 入门学习记录】多节点组网互传消息

本文章使用的例程来自esp-idf的官方例程 vendor_client和vendor_server。

        多个esp32设备想组成mesh网络必须先经过组网,按照乐鑫官方的手册说明,组成网络的需要有一个配网的角色(Provisioner),他负责将搜索到mesh设备配置节点。vendor_client例程刚好就有配网的操作,接下来就以下载vendor_client例程的esp32作为配网器,下载vendor_server例程的多个esp32作为节点使用,让多个esp32的mesh互传消息。

配置网络:

        上电下载vendor_client例程的esp32和下载vendor_server例程的多个esp32就可以开始复杂的配网操作,实际配网逻辑都是官方写好的,要实现多个节点配网只需要把修改uuid就行(这段存疑,若有误请指出),这里我分别把三个下载vendor_server例程的多个esp32的uuid修改成0x3210,0x3211,0x3212然后进行配网。

static uint8_t dev_uuid[ESP_BLE_MESH_OCTET16_LEN] = { 0x32, 0x12 };

这是官方文档给出的配网过程,可以参照日志来了解配网过程。

下面这张图来自vendor_client的搜索vendor_server设备(uuid32 11 cc 7b 5c 25 c3 36 00 00 00 00 00 00 00 00的日志:

ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT​: 这说明了ESP BLE Mesh Provisioner收到了一个未被配置的设备的广播数据包事件。

​​Device address: cc 7b 5c 25 c3 36​:这是未配置设备的设备地址。

​​Address type 0x00, adv type 0x03​:说明设备的地址类型和广播类型。在这个情况中,地址类型为公共设备地址,广播类型为非连接可扫描无定向广播。

​​Device UUID: 32 11 cc 7b 5c 25 c3 36 00 00 00 00 00 00 00 00​:设备的UUID,是设备在网状网络中的唯一标识符。

​​oob info 0x0000, bearer PB-ADV​:提示连接接入点是使用广播承载(PB-ADV),没有外部OOB(out of band)认证方法。

​​ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT, bearer PB-ADV​:提示配网器已经开启了一个使用广播承载的配置链接。

​​ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code 0​:配网器成功地将未配网的设备添加到其设备列表中,执行操作时未报错。

搜索到日志后vendor_client就开始为vendor_server设备(uuid32 11 cc 7b 5c 25 c3 36 00 00 00 00 00 00 00 00进行配网:

节点配置和存储信息

​​node_index 1, primary_addr 0x0006, element_num 1, net_idx 0x0000​: 这表示当前节点(设备)的索引为1,主地址(primary address)是 ​0x0006​,包含的元素数量(element number)是1,网络索引(net_idx)为 ​0x0000​。

​​uuid: 32 11 cc 7b...​: 这是该节点的唯一标识符(UUID),用于在Mesh网络中识别不同的节点。

​​Store, key "vendor_client", length 4​: 这表示使用非易失性存储(NVS)保存了关键词“vendor_client”及其对应的数据长度4字节。

​​Store, data: 06 00 fd 00​: 保存到NVS的数据。

节点命名

​​ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code 0​: 指示已成功设置节点名称的事件,没有错误码(err_code 0表示无错误)。

​​Node 1 name NODE-01​: 节点1被命名为 ​NODE-01​。

组成数据(Composition Data)获取

​​Config client, err_code 0, event 0, addr 0x0006...​: 这表示配置客户端成功运行,无错误发生(​err_code 0​),针对地址 ​0x0006​的节点。

​​Composition data: e5 02 00 00...​: 显示了节点的组成数据,包括公司ID、产品ID、版本ID、功能等信息。这是Mesh网络中节点发布的一种标准数据格式,用于描述节点的能力和功能。

配置客户端回调

​​Config client, err_code 0, event 1...​: 表示另一个配置客户端事件的成功完成。

​​Provision and config successfully​: 提示Provision(配网)和配置流程成功完成。

vendor_client配置设备32 11 cc 7b 5c 25 c3 36 00 00 00 00 00 00 00 00为mesh网络节点成功,网络号为0x0000,地址为0x0005(根据这个地址就可以定向给这个设备发消息了):

这是vendor_server的配网过程的日志:

ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:

表示节点配网完成事件已发生,节点已成功地完成配网过程。

ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT,bearer PB-ADV:

表示配网链接关闭事件,使用的承载协议是 ​PB-ADV​(广播承载器)。

ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:

表示应用程序密钥已添加到设备上。AppKey是用于节点之间通信加密的关键元素。

ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:

表示一个模型与应用程序密钥绑定完成,使模型可以发送和接收经过加密的消息。

net_idx: 网络索引 

addr: 节点地址

flags:  显示配置标志(通常用于标识信息、状态等)

index:  初始向量索引,用于网络层的安全加密。

app_idx: 应用程序索引

AppKey:应用程序密钥的值,它是一系列的字节,用于加密Mesh网络内的消息。

elem_addr: 显示元素地址

app_idx: 应用索引

cid:  公司ID

mod_id: 模型ID

看到以上日志消息说明配网成功。

重复以上步骤(给两个下载vendor_server例程的esp32依次上电)为另外两个设备配上网络,配网成功了就可以进行发送消息了。

vendor_client和vendor_server原例程只提供了server按下boot按键就发送cid给client的逻辑,显然这个逻辑是不能作为正常的蓝牙mesh模组使用的。我们用蓝牙mesh组网的方案一般是MCU+蓝牙模组。所以接下来改进一下vendor_server代码,使模块能完成接收来自串口的数据,然后将数据以泛洪传输的方式发送给mesh网络中的各个节点。

这里直接附上修改后的代码:

vendor_server:

#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"

#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"

#include "esp_ble_mesh_defs.h"
#include "esp_ble_mesh_common_api.h"
#include "esp_ble_mesh_networking_api.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_config_model_api.h"
#include "esp_ble_mesh_local_data_operation_api.h"

#include "board.h"
#include "ble_mesh_example_init.h"

#define TAG "LBC"

#define EX_UART_NUM UART_NUM_0
#define PATTERN_CHR_NUM    (3)         /*!< Set the number of consecutive and identical characters received by receiver which defines a UART pattern*/

#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
static QueueHandle_t uart0_queue;

#define CID_ESP     0x02E5

#define MSG_SEND_TTL        3
#define MSG_SEND_REL        false
#define MSG_TIMEOUT         0
#define MSG_ROLE            ROLE_PROVISIONER

#define ESP_BLE_MESH_VND_MODEL_ID_CLIENT    0x0000
#define ESP_BLE_MESH_VND_MODEL_ID_SERVER    0x0001

#define ESP_BLE_MESH_VND_MODEL_OP_SEND      ESP_BLE_MESH_MODEL_OP_3(0x00, CID_ESP)
#define ESP_BLE_MESH_VND_MODEL_OP_STATUS    ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)



static uint8_t dev_uuid[ESP_BLE_MESH_OCTET16_LEN] = { 0x32, 0x12 };

static esp_ble_mesh_cfg_srv_t config_server = {
    .relay = ESP_BLE_MESH_RELAY_DISABLED,
    .beacon = ESP_BLE_MESH_BEACON_ENABLED,
#if defined(CONFIG_BLE_MESH_FRIEND)
    .friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
#else
    .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
#endif
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
    .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
#else
    .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
    .default_ttl = 7,
    /* 3 transmissions with 20ms interval */
    .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
    .relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
};

static esp_ble_mesh_model_t root_models[] = {
    ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
};

static esp_ble_mesh_model_op_t vnd_op[] = {
    ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_SEND, 2),
    ESP_BLE_MESH_MODEL_OP_END,
};

static esp_ble_mesh_model_t vnd_models[] = {
    ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_SERVER,
    vnd_op, NULL, NULL),
};

static esp_ble_mesh_elem_t elements[] = {
    ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
};

static esp_ble_mesh_comp_t composition = {
    .cid = CID_ESP,
    .elements = elements,
    .element_count = ARRAY_SIZE(elements),
};

static esp_ble_mesh_prov_t provision = {
    .uuid = dev_uuid,
};

static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
{
    ESP_LOGI(TAG, "net_idx 0x%03x, addr 0x%04x", net_idx, addr);
    ESP_LOGI(TAG, "flags 0x%02x, iv_index 0x%08" PRIx32, flags, iv_index);
    board_led_operation(LED_G, LED_OFF);
}

static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
                                             esp_ble_mesh_prov_cb_param_t *param)
{
    switch (event) {
    case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code);
        break;
    case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code);
        break;
    case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
            param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
        break;
    case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
            param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
        break;
    case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
        prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
            param->node_prov_complete.flags, param->node_prov_complete.iv_index);
        break;
    case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_RESET_EVT");
        break;
    case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code);
        break;
    default:
        break;
    }
}

static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
                                              esp_ble_mesh_cfg_server_cb_param_t *param)
{
    if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) {
        switch (param->ctx.recv_op) {
        case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
            ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD");
            ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x",
                param->value.state_change.appkey_add.net_idx,
                param->value.state_change.appkey_add.app_idx);
            ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16);
            break;
        case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
            ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND");
            ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x",
                param->value.state_change.mod_app_bind.element_addr,
                param->value.state_change.mod_app_bind.app_idx,
                param->value.state_change.mod_app_bind.company_id,
                param->value.state_change.mod_app_bind.model_id);
            break;
        default:
            break;
        }
    }
}





void example_ble_mesh_send_vendor_message(bool resend,uint16_t lenght,uint8_t *data)
{
    esp_ble_mesh_msg_ctx_t ctx = {0};
    uint32_t opcode;
    esp_err_t err;

    ctx.net_idx = 0x0000;
    ctx.app_idx = 0x0000;
    ctx.addr = 0xffff;
    ctx.send_ttl = MSG_SEND_TTL;
    ctx.send_rel = MSG_SEND_REL;
    opcode = ESP_BLE_MESH_VND_MODEL_OP_SEND;

    if (resend == false) {
        data[0]++;
    }

    //向client上报消息,其他server收不到
    //err = esp_ble_mesh_server_model_send_msg(&vnd_models[0],&ctx, ESP_BLE_MESH_VND_MODEL_OP_STATUS,lenght, (uint8_t *)data);
    //向其他server发送消息,client收不到
    err = esp_ble_mesh_server_model_send_msg(&vnd_models[0],&ctx, ESP_BLE_MESH_VND_MODEL_OP_SEND,lenght, (uint8_t *)data);
    
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to send vendor message 0x%06" PRIx32, opcode);
        return;
    }
   
    //mesh_example_info_store(); /* Store proper mesh example info */
}

static void example_ble_mesh_custom_model_cb(esp_ble_mesh_model_cb_event_t event,
                                             esp_ble_mesh_model_cb_param_t *param)
{
    switch (event) {
    case ESP_BLE_MESH_MODEL_OPERATION_EVT:
        if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_SEND) 
        {
            //ESP_LOGI(TAG,"Message from: 0x%04x,Message:%s",param->client_recv_publish_msg.ctx->addr,param->client_recv_publish_msg.msg);
            printf("Message from: 0x%04x,Message:%s\n",param->client_recv_publish_msg.ctx->addr,param->client_recv_publish_msg.msg);
            /*uint16_t tid = *(uint16_t *)param->model_operation.msg;
            ESP_LOGI(TAG, "Recv 0x%06" PRIx32 ", tid 0x%04x", param->model_operation.opcode, tid);
            esp_err_t err = esp_ble_mesh_server_model_send_msg(&vnd_models[0],
                    param->model_operation.ctx, ESP_BLE_MESH_VND_MODEL_OP_STATUS,
                    sizeof(tid), (uint8_t *)&tid);
            if (err) {
                ESP_LOGE(TAG, "Failed to send message 0x%06x", ESP_BLE_MESH_VND_MODEL_OP_STATUS);
            }*/
        }
        break;
    case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
        if (param->model_send_comp.err_code) {
            ESP_LOGE(TAG, "Failed to send message 0x%06" PRIx32, param->model_send_comp.opcode);
            break;
        }
        //ESP_LOGI(TAG, "Send 0x%06" PRIx32, param->model_send_comp.opcode);
        printf("Message:%s have been sent to the mesh network\n",param->client_recv_publish_msg.ctx->addr,param->client_recv_publish_msg.msg);
        break;
    default:
        break;
    }
}

static esp_err_t ble_mesh_init(void)
{
    esp_err_t err;

    esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
    esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
    esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);

    err = esp_ble_mesh_init(&provision, &composition);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize mesh stack");
        return err;
    }

    err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to enable mesh node");
        return err;
    }

    board_led_operation(LED_G, LED_ON);

    ESP_LOGI(TAG, "BLE Mesh Node initialized");

    return ESP_OK;
}

static void uart_event_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(uart0_queue, (void * )&event, (TickType_t)portMAX_DELAY)) {
            bzero(dtmp, RD_BUF_SIZE);
            //ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
            switch(event.type) 
            {
                //Event of UART receving data
                case UART_DATA:
                    //ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                    uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
                    //ESP_LOGI(TAG, "[DATA EVT]:");
                    example_ble_mesh_send_vendor_message(true,event.size+1,dtmp);
                    uart_write_bytes(EX_UART_NUM, (const char*) dtmp, event.size);

                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow");
                    // If fifo overflow happened, you should consider adding flow control for your application.
                    // The ISR has already reset the rx FIFO,
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full");
                    // If buffer full happened, you should consider increasing your buffer size
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break");
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error");
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:
                    ESP_LOGI(TAG, "uart frame error");
                    break;
                //UART_PATTERN_DET
                case UART_PATTERN_DET:
                    uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
                    int pos = uart_pattern_pop_pos(EX_UART_NUM);
                    ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                    if (pos == -1) {
                        // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
                        // record the position. We should set a larger queue size.
                        // As an example, we directly flush the rx buffer here.
                        uart_flush_input(EX_UART_NUM);
                    } else {
                        uart_read_bytes(EX_UART_NUM, dtmp, pos, 100 / portTICK_PERIOD_MS);
                        uint8_t pat[PATTERN_CHR_NUM + 1];
                        memset(pat, 0, sizeof(pat));
                        uart_read_bytes(EX_UART_NUM, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
                        ESP_LOGI(TAG, "read data: %s", dtmp);
                        ESP_LOGI(TAG, "read pat : %s", pat);
                    }
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d", event.type);
                    break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

void app_main(void)
{
    esp_err_t err;

    ESP_LOGI(TAG, "Initializing...");

    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };

    //Install UART driver, and get the queue.
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
    uart_param_config(EX_UART_NUM, &uart_config);

    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Set uart pattern detect function.
    uart_enable_pattern_det_baud_intr(EX_UART_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0);
    //Reset the pattern queue length to record at most 20 pattern positions.
    uart_pattern_queue_reset(EX_UART_NUM, 20);

    //Create a task to handler UART event from ISR
    xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL);

    err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    board_init();

    err = bluetooth_init();
    if (err) {
        ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
        return;
    }

    ble_mesh_get_dev_uuid(dev_uuid);

    /* Initialize the Bluetooth Mesh Subsystem */
    err = ble_mesh_init();
    if (err) {
        ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
    }
}

这里加了串口的逻辑和修改了发送的逻辑,把从串口收到信息转发到mesh网络中的server设备(这里不是想只发送给server设备,也想发给client设备,但试过发现,不能同时发,他是下图这种情况,实在搞不清如何做到client和server同时都能收到,欢迎评论区讨论。 ps:试过下面两个函数同时运行,但是会报Ignoring old SeqAuth.的异常)

以下是代码运行截图,主要实现了三个设备互相发消息,模拟MCU给模组发数据,然后模组转发。

这个逻辑实现后就可以加上更多好用的逻辑了,比如加上指令解析,实时获取节点消息和节点状态,选择点对点发送还是群发。

以下是遇到并且还没解决的问题,求大佬解答!

1.大框这个参数是配置设备为client模型还是server模型的,是不是也可以把vendor_client改成server模型?改成server之后还能进行配网吗?未尝试;红色小框的操作码是怎么定的?官方文档没找到。

2.在配网的过程中会出现BLE_MESH: No matching TX context for ack.的异常报错,出现这个的原因是不是我部分数据没配置好导致各节点冲突了?

3.server节点多次密集发同一条信息会出现这样的报错,是ESP BLE MESH的机制问题还是哪里没有设置好?

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值