当前位置: 首页 > news >正文

详细介绍:手把手教你用 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));}
}

http://www.jsqmd.com/news/6761/

相关文章:

  • 完整教程:Python学习历程——组织结构(包含for、if、while等等)
  • Nginx 反向代理、负载均衡与 Keepalived 高可用 - 实践
  • 文件上传攻击全面指南:从侦察到防御
  • 2025年陕西洋房楼盘,西安城西品质楼盘,沣东品牌楼盘住宅口碑推荐,地建嘉信臻境户型多元布局,满足全周期生活需求
  • asus nuc15 pro ultra7 255H 外接 fevm 雷电5显卡坞 BIOS设置
  • P11529 [THUPC 2025 初赛] 辞甲猾扎
  • 2025年陕西品牌楼盘,西安城西优质楼盘,西咸新区核心楼盘住宅口碑推荐,地建嘉信臻境距吾悦广场一路之隔,商业配套完善
  • ARC113E Rvom and Rsrev
  • IDEA 高效配备指南:从基础到进阶的设置全解析
  • Sunny Pro 网络验证- 仅需一键,即可为您的exe添加高强度防破加密!
  • 完整教程:跨会话泄露:AI时代下的安全挑战与防御策略
  • 一条mysql数据库更新语句
  • 浅谈递归入门(1) - 指南
  • python+uniapp基于微信小工具的医院陪诊预约系统
  • 详细介绍:Nginx 访问控制、用户认证与 HTTPS 配置指南
  • comfyui配置
  • [深度学习] 大模型学习5-高效微调框架Unsloth使用指北
  • 前端-JavaScript简介JavaScript模块化 - 努力-
  • gitee 使用安装教程
  • 2025工业网线厂家权威推荐榜:千兆/拖链/高柔/网线/六类/超五类/6类/超5类/千兆/超六类/8芯/4芯/成品/相机/视觉数据工业网线高强屏蔽与稳定传输实力之选
  • VisualMimic——基于视觉的人形行走-操作控制:低层策略负责平衡控制且跟踪高层下发的指令、高层策略则基于自我中心视觉输入生成任务跟踪指令 - 实践
  • FPGA强化-简易频率计 - 实践
  • 基本分页存储管理的基本概念
  • luogu P6503 [COCI 2010/2011 #3] DIFERENCIJA
  • 2025宅基地纠纷律所权威推荐榜:专业调解与胜诉保障实力之选
  • 消逝的光芒困兽脚本更新【2025年10月1日】
  • docker build 时报错 Error fail to solve
  • web图像触发防盗链,无法显示
  • .NET操作Excel:单元格范围 (Range) 的精确定位与常用管理 (下)
  • TCP的学习 - 实践