详细介绍:手把手教你用 ESP32 接入 OneNet 平台(MQTT 方式)

最近折腾了一下 ESP32 和 OneNet 平台的物联网接入,踩了不少坑,干脆整理一下写成一篇教程,大家跟着一步一步操作就能跑通。

本文用到的主要功能有:

  • WiFi STA 模式联网

  • MQTT 协议连接 OneNet

  • 属性上报 / 下发

最后跑通之后,你可以在 OneNet 平台上看到设备数据,还能通过控制台下发属性给 ESP32 响应。


首先在onent平台创建账号进入首页右上角开发者中心

选中左侧产品开发

直接创建产品,跟着后面的图进行选择,产品品类可以随便选或者根据自己需求,然后选设备接入

然后照着下图进行填写,只需要修改产品名称为自己的产品名称

然后选择设备接入管理的设备管理

选择添加设备,所属产品选择前面自己命名的产品名称,设备名称自定义,位置自己选然后确定

然后返回产品开发,选择刚刚创建的产品的产品开发

进入之后选择右侧设置物模型选择自定义功能点,然后根据自己要上传云平台的数据类型进行填写,比如我要上传温度传感器的数据,我就功能名称写temp,标识符写temp,都是可以自定义的,便于自己识别,然后数据类型因为温度为整数所以选择整数,取值范围0-100度,步长为1,单位摄氏度,读写类型可以选择读写或者只读,因为我们只需要读取数据所以都行

选择保存云平台部分就完成了,接下来就是代码部分,直接复制进自己工程就行,

我们主要写了三个模块:

  1. simple_wifi_sta.* —— WiFi 连接管理

  2. onenet.* —— MQTT 接入 OneNet

  3. main.c —— 应用逻辑(初始化 + 数据上报 + 下发回调)

目录大概是这样的:

├── main
│   ├── main.c
│   ├── onenet.c
│   ├── onenet.h
│   ├── simple_wifi_sta.c
│   └── simple_wifi_sta.h
我先讲解需要修改内容,结尾会贴出完整代码

看下 simple_wifi_sta.c,里面做了几件事:优先从 NVS(非易失性存储)里读取 WiFi SSID/密码,如果没有存过,就用默认配置:

#define DEFAULT_WIFI_SSID     "littlecat"
#define DEFAULT_WIFI_PASSWORD "89999999"

这里直接修改成自己的账号密码即可,

接下来重点是 onenet.c。核心就是配置 MQTT 参数:

#define ONENET_PRODUCT_ID   "你的ProductID"
#define ONENET_DEVICE_NAME  "你的DeviceName"
#define ONENET_PASSWORD     "你的鉴权字符串"

这里产品id我们打开产品管理就能看到

设备名即为上图的设备名称/ID部分,根据自己前面自定义的名称填写即可,最后是鉴权字符串,我们需要使用官方文档中的工具,打开文档中心,

左边选择点击下载工具,

res直接填入

products/自己的产品id/devices/自己的设备名

et为服务到期事件戳,写的越长越好,

时间戳(Unix timestamp)转换工具 - 在线工具

我这里直接到28年,然后把转换后的复制进去,然后是key,我们直接进入这个页面的详情,

复制设备密钥填入即可,其他的不用修改,然后生成后把结果复制进代码的鉴权字符串处即可

然后是怎么上发数据,

mqtt_upload_properties(2, "temp", 25, "humi", 60);

修改这部分即可,2和25即为你要上传的值,后的字符串为对应的键值对,即为刚刚在onenet中的物模型,可以按照格式自行拓展,现在贴出所有代码


onenet.c

#include 
#include 
#include 
#include "esp_log.h"
#include "mqtt_client.h"
#include "onenet.h"
#define ONENET_PRODUCT_ID   ""
#define ONENET_DEVICE_NAME  ""
#define ONENET_PASSWORD     ""
#define TOPIC_PROPERTY_POST "$sys/"ONENET_PRODUCT_ID"/"ONENET_DEVICE_NAME"/thing/property/post"
#define TOPIC_PROPERTY_REPLY "$sys/"ONENET_PRODUCT_ID"/"ONENET_DEVICE_NAME"/thing/property/post/reply"
#define TOPIC_PROPERTY_SET   "$sys/"ONENET_PRODUCT_ID"/"ONENET_DEVICE_NAME"/thing/property/set"
static const char *TAG = "ONENET";
static esp_mqtt_client_handle_t client = NULL;
static bool mqtt_connected = false;
static int mqtt_publish_data(const char *topic, const char *data)
{
    if (!client || !mqtt_connected)
    {
        ESP_LOGW(TAG, "MQTT not ready, skip publish");
        return -1;
    }
    int msg_id = esp_mqtt_client_publish(client, topic, data, 0, 1, 0);
    ESP_LOGI(TAG, "Publish topic=%s msg_id=%d", topic, msg_id);
    return msg_id;
}
void mqtt_upload_properties(int count, ...)
{
    va_list args;
    va_start(args, count);
    char data[256];
    int offset = snprintf(data, sizeof(data),
                          "{\"id\":\"123\",\"version\":\"1.0\",\"params\":{");
    for (int i = 0; i < count; i++)
    {
        const char *key = va_arg(args, const char *);
        int value = va_arg(args, int);
        offset += snprintf(data + offset, sizeof(data) - offset,
                           "\"%s\":{\"value\":%d}%s",
                           key, value, (i < count - 1) ? "," : "");
    }
    snprintf(data + offset, sizeof(data) - offset, "}}");
    va_end(args);
    mqtt_publish_data(TOPIC_PROPERTY_POST, data);
}
typedef void (*property_callback_t)(cJSON *value);
typedef struct
{
    const char *key;
    property_callback_t callback;
} property_handler_t;
__attribute__((weak)) void on_temp_change(cJSON *value) { (void)value; }
__attribute__((weak)) void on_humi_change(cJSON *value) { (void)value; }
__attribute__((weak)) void on_key_change(cJSON *value)  { (void)value; }
static property_handler_t property_table[] =
{
    { "temp", on_temp_change },
    { "humi", on_humi_change },
    { "key",  on_key_change },
};
static const int property_count = sizeof(property_table) / sizeof(property_table[0]);
static void mqtt_parse_downlink(const char *data, int len)
{
    char *json_str = strndup(data, len);
    if (!json_str) return;
    cJSON *root = cJSON_Parse(json_str);
    if (!root) { free(json_str); return; }
    cJSON *params = cJSON_GetObjectItem(root, "params");
    if (params)
    {
        for (cJSON *child = params->child; child; child = child->next)
        {
            ESP_LOGI(TAG, "下发属性=%s", child->string);
            for (int i = 0; i < property_count; i++)
            {
                if (strcmp(child->string, property_table[i].key) == 0)
                {
                    property_table[i].callback(child);
                }
            }
        }
    }
    cJSON_Delete(root);
    free(json_str);
}
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_mqtt_event_handle_t event = event_data;
    switch ((esp_mqtt_event_id_t)event_id) {
    case MQTT_EVENT_CONNECTED:
        ESP_LOGI(TAG, "MQTT connected");
        mqtt_connected = true;
        esp_mqtt_client_subscribe(client, TOPIC_PROPERTY_REPLY, 1);
        esp_mqtt_client_subscribe(client, TOPIC_PROPERTY_SET, 1);
        break;
    case MQTT_EVENT_DISCONNECTED:
        ESP_LOGW(TAG, "MQTT disconnected");
        mqtt_connected = false;
        break;
    case MQTT_EVENT_DATA:
        ESP_LOGI(TAG, "MQTT data: %.*s", event->data_len, event->data);
        mqtt_parse_downlink(event->data, event->data_len);
        break;
    default:
        break;
    }
}
void onenet_start(void)
{
    esp_mqtt_client_config_t mqtt_cfg =
    {
        .broker.address.uri = "mqtt://mqtts.heclouds.com:1883",
        .credentials = {
            .username = ONENET_PRODUCT_ID,
            .client_id = ONENET_DEVICE_NAME,
            .authentication.password = ONENET_PASSWORD,
        },
        .session.keepalive = 60,
        .network.disable_auto_reconnect = false,
    };
    client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(client);
}

onenet.h

#ifndef _ONENET_H_
#define _ONENET_H_
#include "cJSON.h"
void onenet_start(void);
void mqtt_upload_properties(int count, ...);
void on_temp_change(cJSON *value);
void on_humi_change(cJSON *value);
void on_key_change(cJSON *value);
#endif

simple_wifi.c

#include "simple_wifi_sta.h"
#include 
#include 
#include 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#define DEFAULT_WIFI_SSID           ""
#define DEFAULT_WIFI_PASSWORD       ""
static const char *TAG = "wifi";
static EventGroupHandle_t wifi_event_group;
const static int CONNECTED_BIT = BIT0;
#define NVS_NAMESPACE "wifi_config"
#define NVS_KEY_SSID "ssid"
#define NVS_KEY_PASSWORD "password"
static esp_err_t read_wifi_config_from_nvs(char *ssid, char *password, size_t max_len)
{
    nvs_handle_t nvs_handle;
    esp_err_t err;
    err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
        return err;
    }
    size_t required_size = 0;
    err = nvs_get_str(nvs_handle, NVS_KEY_SSID, NULL, &required_size);
    if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND)
    {
        ESP_LOGE(TAG, "Error reading SSID from NVS: %s", esp_err_to_name(err));
        nvs_close(nvs_handle);
        return err;
    }
    if (err == ESP_ERR_NVS_NOT_FOUND || required_size == 0)
    {
        ESP_LOGI(TAG, "No SSID found in NVS, using default");
        nvs_close(nvs_handle);
        return ESP_ERR_NVS_NOT_FOUND;
    }
    err = nvs_get_str(nvs_handle, NVS_KEY_SSID, ssid, &max_len);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Error reading SSID value from NVS: %s", esp_err_to_name(err));
        nvs_close(nvs_handle);
        return err;
    }
    err = nvs_get_str(nvs_handle, NVS_KEY_PASSWORD, NULL, &required_size);
    if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND)
    {
        ESP_LOGE(TAG, "Error reading password from NVS: %s", esp_err_to_name(err));
        nvs_close(nvs_handle);
        return err;
    }
    if (err == ESP_ERR_NVS_NOT_FOUND || required_size == 0)
    {
        ESP_LOGI(TAG, "No password found in NVS, using default");
        nvs_close(nvs_handle);
        return ESP_ERR_NVS_NOT_FOUND;
    }
    err = nvs_get_str(nvs_handle, NVS_KEY_PASSWORD, password, &max_len);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Error reading password value from NVS: %s", esp_err_to_name(err));
        nvs_close(nvs_handle);
        return err;
    }
    nvs_close(nvs_handle);
    ESP_LOGI(TAG, "Read WiFi config from NVS: SSID=%s", ssid);
    return ESP_OK;
}
esp_err_t save_wifi_config_to_nvs(const char *ssid, const char *password)
{
    nvs_handle_t nvs_handle;
    esp_err_t err;
    err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
        return err;
    }
    err = nvs_set_str(nvs_handle, NVS_KEY_SSID, ssid);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Error saving SSID to NVS: %s", esp_err_to_name(err));
        nvs_close(nvs_handle);
        return err;
    }
    err = nvs_set_str(nvs_handle, NVS_KEY_PASSWORD, password);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Error saving password to NVS: %s", esp_err_to_name(err));
        nvs_close(nvs_handle);
        return err;
    }
    err = nvs_commit(nvs_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Error committing NVS changes: %s", esp_err_to_name(err));
        nvs_close(nvs_handle);
        return err;
    }
    nvs_close(nvs_handle);
    ESP_LOGI(TAG, "Saved WiFi config to NVS: SSID=%s", ssid);
    return ESP_OK;
}
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT)
    {
        switch (event_id)
        {
            case WIFI_EVENT_STA_START:
                esp_wifi_connect();
                break;
            case WIFI_EVENT_STA_CONNECTED:
                ESP_LOGI(TAG, "connected to AP");
                break;
            case WIFI_EVENT_STA_DISCONNECTED:
                ESP_LOGI(TAG, "connect to the AP fail, retry now");
                vTaskDelay(pdMS_TO_TICKS(2000));
                esp_wifi_connect();
                break;
            default:
                break;
        }
    }
    else if (event_base == IP_EVENT)
    {
        switch(event_id)
        {
            case IP_EVENT_STA_GOT_IP:
                ESP_LOGI(TAG, "get ip address");
                xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
                break;
        }
    }
}
esp_err_t wifi_sta_init(void)
{
    wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
    char ssid[32] = {0};
    char password[64] = {0};
    if (read_wifi_config_from_nvs(ssid, password, sizeof(ssid)) != ESP_OK)
    {
        strncpy(ssid, DEFAULT_WIFI_SSID, sizeof(ssid) - 1);
        strncpy(password, DEFAULT_WIFI_PASSWORD, sizeof(password) - 1);
        ESP_LOGI(TAG, "Using default WiFi config: SSID=%s", ssid);
    }
    wifi_config_t wifi_config =
    {
        .sta = {
            .ssid = "",
            .password = "",
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            .pmf_cfg = {
                .capable = true,
                .required = false
            },
        },
    };
    strncpy((char*)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid) - 1);
    strncpy((char*)wifi_config.sta.password, password, sizeof(wifi_config.sta.password) - 1);
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
    ESP_LOGI(TAG, "wifi_init_sta finished.");
    return ESP_OK;
}

simple_wifi.h

#ifndef _WIFI_MANAGER_H_
#define _WIFI_MANAGER_H_
#include "esp_err.h"
esp_err_t wifi_sta_init(void);
esp_err_t save_wifi_config_to_nvs(const char *ssid, const char *password);
#endif

main.c

#include 
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_random.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "simple_wifi_sta.h"
#include "key.h"
#include "onenet.h"
static const char *TAG = "MAIN";
void on_temp_change(cJSON *value)
{
    if (cJSON_IsNumber(value))
    {
        ESP_LOGI(TAG, "[下发回调] 温度: %d", value->valueint);
    }
}
void on_humi_change(cJSON *value)
{
    if (cJSON_IsNumber(value))
    {
        ESP_LOGI(TAG, "[下发回调] 湿度: %d", value->valueint);
    }
}
void on_key_change(cJSON *value)
{
    if (cJSON_IsNumber(value))
    {
        ESP_LOGI(TAG, "[下发回调] key = %d", value->valueint);
    }
}
void key_task(void *pvParameters)
{
    while (1)
    {
        if (key_getnum() == 1)
        {
            int temp = rand() % 100;
            mqtt_upload_properties(2, "temp", temp, "key", 1);
        }
        vTaskDelay(pdMS_TO_TICKS(50));
    }
}
void app_main(void)
{
    ESP_LOGI(TAG, "[APP] Startup..");
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(wifi_sta_init());
    key_init();
    srand(esp_random());
    onenet_start();
    xTaskCreate(key_task, "key_task", 4096, NULL, 5, NULL);
    while (1)
    {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

posted @ 2025-10-01 12:03  wzzkaifa  阅读(298)  评论(0)    收藏  举报