【ESP32S3】esp32獲取串口數據并通過http上傳到前端

通過前面的學習(前面沒發過,因為其實就是跑它的demo)了解到串口配置以及開啟線程實現功能的工作流程,與此同時還有esp32作為STA節點,將數據通過http發送到服務器。
將這兩者聯合
其實是可以得到一個:esp32獲取串口數據并通過http上傳到前端,這樣的功能的。假設收到的數據是溫濕度數據。
文章食用提醒:
本文用到的ESP框架是ESP-IDF,服務器端處理代碼格式是js,數據庫采用mongoDB。

http part

#define MAX_HTTP_RECV_BUFFER 512
#define MAX_HTTP_OUTPUT_BUFFER 2048static const char *TAG = "HTTP_CLIENT 0313";
static char response_data[1024]; // 自定義緩存空間儲存一次響應數據
static int recived_len = 0;      // 自定義變量儲存一次響應中接收到分片數據的累計偏移
// http客戶端的事件處理回調函數
static esp_err_t http_client_event_handler(esp_http_client_event_t *evt)
{switch (evt->event_id){case HTTP_EVENT_ON_CONNECTED:ESP_LOGI(TAG, "connected to web-server");recived_len = 0;break;case HTTP_EVENT_ON_DATA:if (evt->user_data){memcpy(evt->user_data + recived_len, evt->data, evt->data_len); // 將分片的每一片數據都復制到user_datarecived_len += evt->data_len;//累計偏移更新}break;case HTTP_EVENT_ON_FINISH:ESP_LOGI(TAG, "finished a request and response!");recived_len = 0;break;case HTTP_EVENT_DISCONNECTED:ESP_LOGI(TAG, "disconnected to web-server");recived_len = 0;break;case HTTP_EVENT_ERROR:ESP_LOGE(TAG, "error");recived_len = 0;break;default:break;}return ESP_OK;
}
char* create_json_from_data(float temperature, float humidity) {// 創建根對象cJSON *root = cJSON_CreateObject();// 向JSON對象中添加鍵值對cJSON_AddNumberToObject(root, "temperature", temperature);cJSON_AddNumberToObject(root, "humidity", humidity);// 將cJSON對象轉換為字符串char *json_data = cJSON_Print(root);// 釋放cJSON對象占用的內存cJSON_Delete(root);return json_data;
}

uart part

#define CONFIG_UART_TXD 4
#define CONFIG_UART_RXD 5
#define UART_PIN_RTS (-1)
#define UART_PIN_CTS (-1)
#define CONFIG_UART_PORT_NUM      2
#define CONFIG_UART_BAUD_RATE     115200
#define CONFIG_TASK_STACK_SIZE    3072
#define BUF_SIZE (1024)
#define QUEUE_LENGTH 10
static QueueHandle_t xQueue = NULL;
// 假設收到的數據是溫濕度數據
typedef struct data_dht11
{float temperature;float humidity;
}data_t;static void uart_rx_task(void *arg) 
{// 配置串口uart_config_t uart_config = {.baud_rate = CONFIG_UART_BAUD_RATE,.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,};int intr_alloc_flags = 0;#if CONFIG_UART_ISR_IN_IRAMintr_alloc_flags = ESP_INTR_FLAG_IRAM;#endifESP_ERROR_CHECK(uart_driver_install(CONFIG_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, 0));ESP_ERROR_CHECK(uart_param_config(CONFIG_UART_PORT_NUM, &uart_config));ESP_ERROR_CHECK(uart_set_pin(CONFIG_UART_PORT_NUM, CONFIG_UART_TXD, CONFIG_UART_RXD, UART_PIN_RTS, UART_PIN_CTS));uint8_t *data = (uint8_t *)malloc(BUF_SIZE);// 接收數據,把數據存放在隊列里while (1) {int len = uart_read_bytes(CONFIG_UART_PORT_NUM, data, (BUF_SIZE - 1), 20 / portTICK_PERIOD_MS);if(len > 0) {data[len] = '\0';data_t item;sscanf((char*)data, "%f %f", &item.temperature, &item.humidity); // 假設數據格式為"temperature humidity"xQueueSend(xQueue, &item, portMAX_DELAY);}vTaskDelay(pdMS_TO_TICKS(10)); // 讓出CPU時間片,分給其他任務}free(data);
}

main part

void app_main(void)
{esp_err_t ret;nvs_flash_init();esp_netif_init();esp_event_loop_create_default();example_connect();xQueue = xQueueCreate(QUEUE_LENGTH, sizeof(data_t));if (xQueue == NULL) {ESP_LOGE(TAG, "Failed to create queue");return;}xTaskCreate(uart_rx_task, "uart_rx_task", 2048, NULL, configMAX_PRIORITIES-1, NULL);// http配置const esp_http_client_config_t cfg = {.url = "http://124.223.186.76:3000",.event_handler = http_client_event_handler,.user_data = response_data,.disable_auto_redirect = true, // 根據需求選擇是否禁用自動重定向.transport_type = HTTP_TRANSPORT_OVER_TCP, // 強制使用TCP傳輸.timeout_ms = 10000, // 設置超時時間為10秒};//使用http服務器配置參數對http客戶端初始化esp_http_client_handle_t httpclient = esp_http_client_init(&cfg);// 進入循環接收串口數據并發給服務器上while (true) {data_t item;if(xQueueReceive(xQueue, &item, portMAX_DELAY) == pdPASS){// 調用函數創建JSON格式的數據char *json_data = create_json_from_data(item.temperature, item.humidity);// 設置HTTP請求的各種參數esp_http_client_set_method(httpclient, HTTP_METHOD_POST);esp_http_client_set_url(httpclient, "/add");// 添加或更新"Connection"頭為"close"esp_http_client_set_header(httpclient, "Connection", "close");// 設置請求頭esp_http_client_set_header(httpclient, "Content-Type", "application/json");// 設置請求體為剛剛創建的JSON數據esp_http_client_set_post_field(httpclient, json_data, strlen(json_data));// 初始化重試計數器int max_retries = 3; // 最大重試次數esp_err_t ret;for(int retry = 0; retry <= max_retries; ++retry) {ret = esp_http_client_perform(httpclient);if(ret == ESP_OK) {// 請求成功,打印響應數據printf("POST:%s\n", response_data);ESP_LOGD(TAG,"HTTP POST Status = %d, content_length = %lld",esp_http_client_get_status_code(httpclient),esp_http_client_get_content_length(httpclient));break; // 成功后退出循環} else {if(retry < max_retries) {// 如果還有剩余重試次數,則等待一段時間后重試ESP_LOGW(TAG, "Attempt %d failed, retrying in 1 second...", retry + 1);vTaskDelay(pdMS_TO_TICKS(1000)); // 等待1秒后再重試} else {// 達到最大重試次數,記錄錯誤信息ESP_LOGE(TAG, "Error occurred during HTTP request after %d retries, failed: %s", max_retries, esp_err_to_name(ret));}}}free(json_data); // 釋放動態分配的內存}else {// 處理超時或其他錯誤情況ESP_LOGW(TAG, "Failed to receive data from queue.");}}esp_http_client_cleanup(httpclient);//清空http客戶端描述符vQueueDelete(xQueue); // 刪除隊列
}

merge code

const express = require('express')
const bodyParser = require('body-parser')
const { MongoClient } = require('mongodb');
const request = require('request')
const fs = require('fs')const app = express()
app.use(bodyParser.json())// MongoDB URI 和客戶端初始化
const uri = "mongodb://admin:123456@localhost:27017/myDatabase?authSource=admin";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });let db; // 定義一個變量用于存儲數據庫引用async function startServer() {try {await client.connect(); // 連接到MongoDBconsole.log("Connected to database");db = client.db('myDatabase'); // 獲取數據庫引用// 監聽端口app.listen(3000, '0.0.0.0', () => {console.log('mwt server running at http://124.223.186.76:3000');});} catch (err) {console.error("Failed to connect to the database:", err);process.exit(1); // 如果無法連接數據庫,則退出程序}
}startServer();app.get('/add', (req, res) => {const x = req.query.x;const y = req.query.y;if (!x || !y) {return res.status(400).json({ result: false, message: "Missing parameters" });}res.json({result: true,method: "GET",message: Number(x) + Number(y)});
});// 處理外設數據上傳的POST請求
app.post('/add', async (req, res) => {const data = req.body; // 直接獲取到JSON對象console.log("Received data:", data); // 新增日志記錄if (!data.temperature || !data.humidity) {return res.status(400).json({ result: false, message: "Missing parameters" });}try {if (!db) {return res.status(500).json({ result: false, message: "Database connection not established" });}// 插入文檔到集合'readings'const collection = db.collection('readings'); // 使用之前定義的db變量await collection.insertOne(data);console.log(`A document was inserted with the _id: ${data._id}`);// 寫到當前路徑下的log里fs.appendFile('sensor_data.log', JSON.stringify(data) + '\n', (err) => {if (err) throw err;});res.json({result: true,method: "POST",message: "Data received and saved successfully"});} catch (err) {console.error("Failed to save data:", err.stack);res.status(500).json({ result: false, message: "Failed to save data" });}
});// 獲取所有讀數并顯示在前端
app.get('/readings', async (req, res) => {try {const collection = db.collection('readings');// 查找所有文檔const readings = await collection.find({}).toArray();// 返回HTML頁面或JSON數據res.send(`<html><head><title>Sensor Readings</title></head><body><h1>Sensor Readings</h1><ul>${readings.map(r => `<li>Temperature: ${r.temperature}, Humidity: ${r.humidity}</li>`).join('')}</ul></body></html>`);} catch (err) {console.error("Failed to fetch data:", err);res.status(500).send("Error fetching data");}
});

接著在Linux下寫服務器的處理內容

index.js code

const express = require('express')
const bodyParser = require('body-parser')
const { MongoClient } = require('mongodb');
const request = require('request')
const fs = require('fs')const app = express()
app.use(bodyParser.json())// MongoDB URI 和客戶端初始化,這里的賬號密碼記得填你自己的
const uri = "mongodb://yourusername:yourpasswd@localhost:27017/myDatabase?authSource=admin";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });let db; // 定義一個變量用于存儲數據庫引用async function startServer() {try {await client.connect(); // 連接到MongoDBconsole.log("Connected to database");db = client.db('myDatabase'); // 獲取數據庫引用,這里的myDatabase是數據庫名// 監聽端口app.listen(3000, '0.0.0.0', () => {console.log('mwt server running at http://124.223.186.76:3000');});} catch (err) {console.error("Failed to connect to the database:", err);process.exit(1); // 如果無法連接數據庫,則退出程序}
}startServer();// 處理外設數據上傳的POST請求
app.post('/add', async (req, res) => {const data = req.body; // 直接獲取到JSON對象console.log("Received data:", data); // 新增日志記錄if (!data.temperature || !data.humidity) {return res.status(400).json({ result: false, message: "Missing parameters" });}try {if (!db) {return res.status(500).json({ result: false, message: "Database connection not established" });}// 插入文檔到集合'readings'const collection = db.collection('readings'); // 使用之前定義的db變量,這里的readings是表名await collection.insertOne(data);console.log(`A document was inserted with the _id: ${data._id}`);// 寫到當前路徑下的log里fs.appendFile('sensor_data.log', JSON.stringify(data) + '\n', (err) => {if (err) throw err;});res.json({result: true,method: "POST",message: "Data received and saved successfully"});} catch (err) {console.error("Failed to save data:", err.stack);res.status(500).json({ result: false, message: "Failed to save data" });}
});
// 獲取所有讀數并簡單地顯示在前端,也可以另創一個html文件或新建一個web工程按實際情況導進去
app.get('/readings', async (req, res) => {try {const collection = db.collection('readings');  //表名是readings// 查找所有文檔const readings = await collection.find({}).toArray();// 返回HTML頁面或JSON數據res.send(`<html><head><title>Sensor Readings</title></head><body><h1>Sensor Readings</h1><ul>${readings.map(r => `<li>Temperature: ${r.temperature}, Humidity: ${r.humidity}</li>`).join('')}</ul></body></html>`);} catch (err) {console.error("Failed to fetch data:", err);res.status(500).send("Error fetching data");}
});

在服務器部署nodejs,并安裝配置mongoDB環境,這樣前端就可以從mongoDB拿到數據并顯示出來了。
假設已經安裝好nodejs,也裝好了mongoDB。
新建一個目錄,我這里叫my_node_app0314,然后把上面的js處理腳本放進這個文件夾里,這里我把它命名為index.js
1
然后啟動應用

node index.js

如果看到active running就說明啟動好了

ubuntu@VM-12-13-ubuntu:~$ sudo systemctl status my_node_app0314.service # 看狀態
● my_node_app0314.service - My Node.js ApplicationLoaded: loaded (/etc/systemd/system/my_node_app0314.service; enabled; vendor preset: enabled)Active: active (running) since Fri 2025-03-21 10:43:59 CST; 24s agoMain PID: 316472 (node)Tasks: 11 (limit: 8816)Memory: 24.6MCGroup: /system.slice/my_node_app0314.service└─316472 /usr/bin/node /home/ubuntu/my_node_app0314/index.jsMar 21 10:43:59 VM-12-13-ubuntu systemd[1]: Started My Node.js Application.
Mar 21 10:44:00 VM-12-13-ubuntu node[316472]: (node:316472) [MONGODB DRIVER] Warning: useNewUrlParser i>
Mar 21 10:44:00 VM-12-13-ubuntu node[316472]: (Use `node --trace-warnings ...` to show where the warnin>
Mar 21 10:44:00 VM-12-13-ubuntu node[316472]: (node:316472) [MONGODB DRIVER] Warning: useUnifiedTopolog>
Mar 21 10:44:00 VM-12-13-ubuntu node[316472]: Connected to database
Mar 21 10:44:00 VM-12-13-ubuntu node[316472]: mwt server running at http://124.223.186.76:3000
lines 1-15/15 (END)

最后

編譯運行esp32s3,并打開瀏覽器
3
很好的是esp32s3支持很多的i2c擴展,我這里用串口只是為了方便,dht11是單總線的,以上數據來自串口助手。
【全文完】

參考鏈接

:ESP32+idf開發之WIFI通信入門(5)HTTP通信
跑了參考鏈接的代碼
這個博主的文章代碼親測可用,在這里也很謝謝他。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/74489.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74489.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/74489.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《鴻蒙攜手AI:解鎖智慧出行底層邏輯》

在科技飛速發展的當下&#xff0c;智慧出行成為人們對未來交通的美好期許&#xff0c;而鴻蒙系統與人工智能的深度融合&#xff0c;正為這一愿景的實現提供強大助力。從技術原理角度深入剖析&#xff0c;鴻蒙系統究竟如何支撐人工智能在智慧出行場景中的應用呢&#xff1f;這背…

MyBatis-Plus緩存機制深度解析與SpringBoot整合實戰

一、MyBatis-Plus緩存機制全景解析 MyBatis-Plus在MyBatis原生緩存基礎上進行了深度增強,形成了多層次的緩存體系: 1. 緩存層級架構 應用層 ├── MP擴展緩存(多租戶/邏輯刪除) ├── 二級緩存(Mapper級別,跨Session共享) └── 一級緩存(SqlSession級別,默認開…

Day38 | 1365. 有多少小于當前數字的數字、941. 有效的山脈數組、1207. 獨一無二的出現次數、283. 移動零、189. 輪轉數組

1365. 有多少小于當前數字的數字 題目鏈接&#xff1a;1365. 有多少小、于當前數字的數字 - 力扣&#xff08;LeetCode&#xff09; 題目難度&#xff1a;簡單 代碼&#xff1a; class Solution {public int[] smallerNumbersThanCurrent(int[] nums) {Map<Integer,Inte…

數據人的進階之路:四年數倉實踐與成長思考

前言 在數據倉庫開發的過程中&#xff0c;常常會遇到很多值得思考的問題&#xff0c;它們不僅關乎技術的深度&#xff0c;也涉及業務理解、個人的成長&#xff0c;甚至是數據行業未來的價值。回顧過去的經歷&#xff0c;有很多問題反復出現&#xff0c;甚至成為繞不開的課題&am…

大文件分片上傳及斷點續傳實現

使用 支持分片上傳及斷點續傳 前端使用 vue 2 后端使用 springboot 源碼在私信

圖解AUTOSAR_SWS_IOHardwareAbstraction

AUTOSAR IO硬件抽象層詳解 基于AUTOSAR標準的IO硬件抽象層設計與實現指南 目錄 1. 概述2. 架構設計 2.1 模塊架構概覽2.2 內部組件結構2.3 與其他模塊的交互接口 3. 狀態機 3.1 狀態定義3.2 狀態轉換3.3 狀態行為 4. ADC信號處理流程 4.1 初始化流程4.2 轉換請求和處理4.3 通知…

Python正則表達式(一)

目錄 一、正則表達式的基本概念 1、基本概念 2、正則表達式的特殊字符 二、范圍符號和量詞 1、范圍符號 2、匹配漢字 3、量詞 三、正則表達式函數 1、使用正則表達式&#xff1a; 2、re.match()函數 3、re.search()函數 4、findall()函數 5、re.finditer()函數 6…

北京交通大學第三屆C語言積分賽

作者有言在先&#xff1a; 題解的作用是交流思路&#xff0c;不是抄作業的。可以把重點放在思路分析上而不是代碼上&#xff0c;畢竟每個人的代碼風格是不一樣的&#xff0c;看別人的代碼就跟做程序填空題一樣。先看明白思路再看代碼。 還有就是&#xff0c;deepseek真的很好用…

機器學習之條件概率

1. 引言 概率模型在機器學習中廣泛應用于數據分析、模式識別和推理任務。本文將調研幾種重要的概率模型,包括EM算法、MCMC、樸素貝葉斯、貝葉斯網絡、概率圖模型(CRF、HMM)以及最大熵模型,介紹其基本原理、算法流程、應用場景及優勢。 2. EM算法(Expectation-Maximizati…

硬件基礎--03_電流

電流 十九世紀初:[電流方向]是指正電荷的移動方向。 后來:對于金屬導體&#xff0c;正電荷沒移動&#xff0c;其實是電子在移動。 為了定義的統一性[電流方向]仍然定義為正電荷的移動方向 所以:[電流方向]與[電子移動方向]是相反的。 概念:電荷的定向移動&#xff0c;形成了電…

multi paxos協議

1. Redo Log 同步的核心目標 ?數據一致性&#xff1a;確保所有副本在事務提交后具有相同的數據視圖。?容錯性&#xff1a;在主副本故障時&#xff0c;從副本能快速接管并恢復數據。?高吞吐&#xff1a;通過批量同步和并行處理提升效率。 2. Multi Paxos 協議的同步流程 M…

借壹起航東風,中國工廠出海開啟新征程

在經濟全球化不斷深入的當下&#xff0c;中國工廠正以積極的姿態投身海外市場&#xff0c;渴望在全球商業版圖中占據一席之地&#xff0c;綻放獨特的光彩。然而&#xff0c;出海之路充滿了挑戰與艱辛&#xff0c;品牌塑造困難重重、詢盤量不穩定、營銷成本居高不下等問題&#…

【MySQL】監控MySQL

目錄 使用狀態變量監控MySQL 使用性能模式&#xff08;Performance Schema&#xff09;監控MySQL 1.性能模式 2.性能模式設置表 3.sys模式 使用狀態變量監控MySQL 使用 show status 語句評估系統運行狀況。 可以添加范圍修飾符global或session來顯示全局或本地狀態信息。…

在linux系統上卸載并重新安裝Docker及配置國內鏡像源指

前言 Docker 作為容器化技術的核心工具&#xff0c;廣泛應用于開發、測試和部署環境。但在某些情況下&#xff08;如版本沖突、配置錯誤等&#xff09;&#xff0c;可能需要徹底卸載并重新安裝 Docker。此外&#xff0c;國內用戶直接訪問 Docker 官方鏡像源可能速度較慢&#…

Mysql內置函數篇

&#x1f3dd;?專欄&#xff1a;Mysql_貓咪-9527的博客-CSDN博客 &#x1f305;主頁&#xff1a;貓咪-9527-CSDN博客 “欲窮千里目&#xff0c;更上一層樓。會當凌絕頂&#xff0c;一覽眾山小。” 目錄 7.函數 7.1 日期函數 函數總&#xff1a;?編輯 獲得當前日期 獲得…

小愛控制OK影視搜索視頻

在adb connect ip以后&#xff0c;可以這樣打開Ok影視&#xff0c;并且進行控制 pm list packages -3 #只顯示第三方 dumpsys package com.fongmi.android.tv |grep Activity #返回 com.fongmi.android.tv/.ui.activity.HomeActivity am start -n com.fongmi.android.tv/.u…

電機倍頻曲線的一些奇異特性-原因分析及應用

這里對感應電機倍頻曲線的特征進行了說明&#xff0c;然后將其特性用于電機轉差率和工況的測量。先給出可以直接利用的結論&#xff1a; 電機的工況和轉差率譜線會體現為5x,7x譜線調制在基頻附近。兩條調制過攜帶s信息的譜線距離基頻譜線的距離。 與真實轉速相對同步轉速的頻差…

雙指針技巧在C++中的應用:從基礎到進階

目錄 1.簡介 2.同向雙指針 2.1.數組去重 2.2.最大子數組和 2.3.鏈表反轉 2.4.字符串匹配&#xff08;簡單版&#xff09; 3.對向雙指針 3.1.兩數之和&#xff08;有序數組&#xff09; 3.2.盛最多水的容器 4.快慢指針 4.1.判斷鏈表是否有環 4.2.尋找鏈表的中間節點…

語言解碼雙生花:人類經驗與AI算法的鏡像之旅

大家好&#xff0c;我是吾鳴。 今天吾鳴要給大家分享一份由浙江大學出品的DeepSeek報告&#xff0c;報告從語言的奧秘&#xff0c;人類是如何通過語言來解碼世界&#xff0c;AI又是如何理解人類的語言&#xff0c;同時介紹了當下爆火的DeepSeek-V3和DeepSeek-R1兩種大模型的進化…

如何避免測試數據準備不充分或不可復用

避免測試數據準備不充分或不可復用的關鍵方法包括明確數據需求、統一數據管理工具、建立數據復用機制、定期維護更新測試數據以及加強團隊溝通與協作。 其中&#xff0c;統一數據管理工具對確保數據質量和復用性尤為重要。例如&#xff0c;許多團隊采用專門的測試數據管理工具以…