对于不同的消息类型,API 如下:
消息类型 HTTP Method HTTP URL
设备上报属性 POST /device/v1//attributes
设备获取属性 GET /device/v1//attributes
设备上报事件 POST /device/v1//event/report
您只需要将以上的 HTTP URL 和接入点拼接即可获得最终 API URL,例如:
https:///device/v1//attributes
包括 HTTP 和 HTTPs 在内,调用设备访问 API 时,需要通过在 HTTP header
中加入 Project-Key
字段来配合云平台完成设备身份认证。如下:
Content-Type: application/json
Project-Key: >
基于以上信息,给我编写esp32-s3的idf例程,使用post和get两种方式请求数据,写出上传和下发的函数代码,对下发的json数据进行解析,以温度,湿度两种数据为例,对数据进行输出到端口
以下是基于 ESP32-S3 IDF 的例程示例,包括使用 POST 和 GET 请求方式上传和获取数据,并解析下发的 JSON 数据,将温度和湿度输出到端口。
首先,在 main.c
文件中添加以下代码:
#include
#include
#include
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_http_client.h"
#include "cJSON.h"
// WiFi配置
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
// 云平台访问信息
#define ENDPOINT "YOUR_ENDPOINT"
#define ACCESS_TOKEN "YOUR_ACCESS_TOKEN"
#define PROJECT_KEY "YOUR_PROJECT_KEY"
// 上报数据间隔时间(毫秒)
#define REPORT_INTERVAL 5000
static const char *TAG = "ESP32-S3";
// WiFi连接回调函数
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
ESP_LOGI(TAG, "Wi-Fi started");
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_CONNECTED:
ESP_LOGI(TAG, "Wi-Fi connected");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "Wi-Fi disconnected");
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "Obtained IP address");
break;
default:
break;
}
return ESP_OK;
}
// HTTP POST请求回调函数
static esp_err_t http_post_event_handler(esp_http_client_event_t *evt)
{
switch (evt->event_id) {
case HTTP_EVENT_ON_DATA:
ESP_LOGI(TAG, "Received data: %.*s", evt->data_len, (char*)evt->data);
// 解析JSON数据
cJSON *json = cJSON_Parse((char*)evt->data);
if (json == NULL) {
ESP_LOGE(TAG, "Failed to parse JSON data");
break;
}
cJSON *temperature = cJSON_GetObjectItemCaseSensitive(json, "temperature");
cJSON *humidity = cJSON_GetObjectItemCaseSensitive(json, "humidity");
if (cJSON_IsNumber(temperature)) {
ESP_LOGI(TAG, "Temperature: %.2f", temperature->valuedouble);
}
if (cJSON_IsNumber(humidity)) {
ESP_LOGI(TAG, "Humidity: %.2f", humidity->valuedouble);
}
cJSON_Delete(json);
break;
default:
break;
}
return ESP_OK;
}
// HTTP GET请求回调函数
static esp_err_t http_get_event_handler(esp_http_client_event_t *evt)
{
switch (evt->event_id) {
case HTTP_EVENT_ON_DATA:
ESP_LOGI(TAG, "Received data: %.*s", evt->data_len, (char*)evt->data);
// 解析JSON数据
cJSON *json = cJSON_Parse((char*)evt->data);
if (json == NULL) {
ESP_LOGE(TAG, "Failed to parse JSON data");
break;
}
cJSON *temperature = cJSON_GetObjectItemCaseSensitive(json, "temperature");
cJSON *humidity = cJSON_GetObjectItemCaseSensitive(json, "humidity");
if (cJSON_IsNumber(temperature)) {
ESP_LOGI(TAG, "Temperature: %.2f", temperature->valuedouble);
}
if (cJSON_IsNumber(humidity)) {
ESP_LOGI(TAG, "Humidity: %.2f", humidity->valuedouble);
}
cJSON_Delete(json);
break;
default:
break;
}
return ESP_OK;
}
// 上报数据函数
void upload_data(void)
{
// 创建JSON数据
cJSON *json = cJSON_CreateObject();
cJSON_AddNumberToObject(json, "temperature", 25.0);
cJSON_AddNumberToObject(json, "humidity", 50.0);
char *json_str = cJSON_PrintUnformatted(json);
cJSON_Delete(json);
// 构建HTTP POST请求URL
char url[128];
snprintf(url, sizeof(url), "https://%s/device/v1/%s/attributes", ENDPOINT, ACCESS_TOKEN);
// 配置HTTP请求参数
esp_http_client_config_t config = {
.url = url,
.event_handler = http_post_event_handler,
.method = HTTP_METHOD_POST,
.timeout_ms = 5000,
.buffer_size = 1024,
.headers = {
.content_type = "application/json",
.project_key = PROJECT_KEY,
.project_key_len = strlen(PROJECT_KEY),
},
};
// 发送HTTP POST请求
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_post_field(client, json_str, strlen(json_str));
esp_http_client_perform(client);
esp_http_client_cleanup(client);
free(json_str);
}
// 获取数据函数
void get_data(void)
{
// 构建HTTP GET请求URL
char url[128];
snprintf(url, sizeof(url), "https://%s/device/v1/%s/attributes", ENDPOINT, ACCESS_TOKEN);
// 配置HTTP请求参数
esp_http_client_config_t config = {
.url = url,
.event_handler = http_get_event_handler,
.method = HTTP_METHOD_GET,
.timeout_ms = 5000,
.buffer_size = 1024,
.headers = {
.content_type = "application/json",
.project_key = PROJECT_KEY,
.project_key_len = strlen(PROJECT_KEY),
},
};
// 发送HTTP GET请求
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_perform(client);
esp_http_client_cleanup(client);
}
// 主任务
void app_main(void)
{
// 初始化非易失性存储(NVS)
nvs_flash_init();
// 初始化TCP/IP堆栈
tcpip_adapter_init();
// 注册WiFi事件处理程序
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
// 等待连接到WiFi网络
ESP_LOGI(TAG, "Waiting for Wi-Fi connection...");
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (wifi_is_connected()) {
ESP_LOGI(TAG, "Connected to Wi-Fi");
break;
}
}
// 循环上报数据和获取数据
while (1) {
upload_data();
get_data();
vTaskDelay(REPORT_INTERVAL / portTICK_PERIOD_MS);
}
}
请确保将代码中的以下占位符替换为您的实际信息:
YOUR_WIFI_SSID
:您的Wi-Fi SSID。YOUR_WIFI_PASSWORD
:您的Wi-Fi密码。YOUR_ENDPOINT
:云平台的访问端点。YOUR_ACCESS_TOKEN
:设备的访问令牌。YOUR_PROJECT_KEY
:云平台的项目密钥。这段代码使用了 ESP-IDF 中的 WiFi 和 HTTP Client 组件,通过 Wi-Fi 连接到网络,然后循环执行上报数据和获取数据的函数。上传数据使用 HTTP POST 请求,将温度和湿度作为 JSON 数据发送到指定的 API URL。获取数据使用 HTTP GET 请求,从指定的 API URL 获取返回的 JSON 数据,并解析出温度和湿度值。最后,将温度和湿度值输出到端口。
SS_TOKEN`:设备的访问令牌。
YOUR_PROJECT_KEY
:云平台的项目密钥。这段代码使用了 ESP-IDF 中的 WiFi 和 HTTP Client 组件,通过 Wi-Fi 连接到网络,然后循环执行上报数据和获取数据的函数。上传数据使用 HTTP POST 请求,将温度和湿度作为 JSON 数据发送到指定的 API URL。获取数据使用 HTTP GET 请求,从指定的 API URL 获取返回的 JSON 数据,并解析出温度和湿度值。最后,将温度和湿度值输出到端口。
请注意,此例程仅作为参考示例,具体实现可能需要根据您的实际需求进行适当修改和调整。