ESP-idf框架下的HTTP服务器\HTML 485温湿度采集并长传

项目描述:

本项目采用485采集温湿度以及电压电流等,485模块分别为下图,串口转485模块采用自动收发模块,ESP32工作在AP热点模式,通过手机连接esp32的热点来和esp进行数据通讯,

使用esp32作为HTTP服务器

缺陷:

项目的最终HTML页面

代码

可发给AI让其写注释

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include <esp_http_server.h>
#include <stdio.h>
#include <string.h>
#include "freertos/queue.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "cJSON.h"
#include <time.h>

/* 配置参数 */
#define EXAMPLE_ESP_WIFI_SSID      "laotie666"
#define EXAMPLE_ESP_WIFI_PASS      "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL   1
#define EXAMPLE_MAX_STA_CONN       4
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN  (64)

#define EX_UART_NUM UART_NUM_1
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)

/* 全局变量 */
uint8_t get_jsy_value[8] = {0x02, 0x03, 0x00, 0x48, 0x00, 0x05, 0x05, 0xEC};
uint8_t get_val[8] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B};
uint16_t Hum = 255;   // 湿度值 Hum = 实际值 * 10
int16_t Tem = 232;    // 温度值 Tem = 实际值 * 10
uint16_t Voltage=24, Current=2;
float Power=2.3;          // 功率

static QueueHandle_t uart0_queue;
static const char *TAG = "wifi softAP";

/* 美观的HTML页面模板 */
static const char *HTML_PAGE = R"rawliteral(
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ESP32 环境监测</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        
        .container {
            background: rgba(255, 255, 255, 0.15);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            width: 100%;
            max-width: 500px;
            padding: 30px;
            color: white;
        }
        
        header {
            text-align: center;
            margin-bottom: 30px;
        }
        
        h1 {
            font-size: 28px;
            margin-bottom: 10px;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
        }
        
        .status {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            font-size: 16px;
        }
        
        .status-indicator {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background-color: #4CAF50;
            box-shadow: 0 0 10px #4CAF50;
        }
        
        .sensors-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }
        
        .sensor-card {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 15px;
            padding: 20px;
            text-align: center;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            cursor: pointer;
        }
        
        .sensor-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
            background: rgba(255, 255, 255, 0.2);
        }
        
        .sensor-icon {
            font-size: 40px;
            margin-bottom: 15px;
        }
        
        .sensor-value {
            font-size: 32px;
            font-weight: bold;
            margin: 10px 0;
        }
        
        .sensor-unit {
            font-size: 16px;
            opacity: 0.8;
        }
        
        .sensor-title {
            font-size: 18px;
            margin-bottom: 10px;
            color: #FFD700;
        }
        
        .power-section {
            background: rgba(0, 0, 0, 0.2);
            border-radius: 15px;
            padding: 20px;
            margin-bottom: 25px;
        }
        
        .power-title {
            text-align: center;
            font-size: 20px;
            margin-bottom: 15px;
            color: #FFD700;
        }
        
        .power-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 15px;
        }
        
        .power-card {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 10px;
            padding: 15px;
            text-align: center;
        }
        
        .power-value {
            font-size: 24px;
            font-weight: bold;
            margin: 5px 0;
        }
        
        .power-label {
            font-size: 14px;
            opacity: 0.8;
        }
        
        .last-update {
            text-align: center;
            font-size: 14px;
            opacity: 0.7;
            margin-top: 20px;
        }
        
        .refresh-info {
            text-align: center;
            font-size: 14px;
            margin-top: 10px;
            opacity: 0.7;
        }
        
        footer {
            text-align: center;
            margin-top: 30px;
            font-size: 14px;
            opacity: 0.8;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>ESP32 环境监测</h1>
            <div class="status">
                <div class="status-indicator"></div>
                <span>设备在线</span>
            </div>
        </header>
        
        <div class="sensors-grid">
            <div class="sensor-card" style="border: 2px solid #FF5252;">
                <div class="sensor-icon">🌡️</div>
                <div class="sensor-title">温度</div>
                <div class="sensor-value">%.1f</div>
                <div class="sensor-unit">°C</div>
            </div>
            
            <div class="sensor-card" style="border: 2px solid #29B6F6;">
                <div class="sensor-icon">💧</div>
                <div class="sensor-title">湿度</div>
                <div class="sensor-value">%.1f</div>
                <div class="sensor-unit">%</div>
            </div>
        </div>
        
        <div class="power-section">
            <div class="power-title">电能参数</div>
            <div class="power-grid">
                <div class="power-card">
                    <div class="power-label">电压</div>
                    <div class="power-value">%d</div>
                    <div class="power-unit">V</div>
                </div>
                
                <div class="power-card">
                    <div class="power-label">电流</div>
                    <div class="power-value">%.1f</div>
                    <div class="power-unit">A</div>
                </div>
                
                <div class="power-card">
                    <div class="power-label">功率</div>
                    <div class="power-value">%.1f</div>
                    <div class="power-unit">W</div>
                </div>
            </div>
        </div>
        
        <div class="last-update">最后更新: %s</div>
        <div class="refresh-info">页面每2秒自动刷新</div>
        
        <footer>
            ESP32 环境监测系统 | © 2025
        </footer>
    </div>
    
    <script>
        // 每2秒自动刷新页面
        setTimeout(function() {
            location.reload();
        }, 2000);
    </script>
</body>
</html>
)rawliteral";

/* 获取当前时间字符串 */
static const char *get_current_time() {
    static char time_str[20];
    time_t now = time(NULL);
    struct tm *timeinfo = localtime(&now);
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", timeinfo);
    return time_str;
}

/* UART事件处理任务 */
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 (;;) {
        if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
            bzero(dtmp, RD_BUF_SIZE);
            
            switch (event.type) {
                case UART_DATA:
                    uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
                    
                    if (event.size == 15) {
                        Voltage = dtmp[3];
                        Voltage = Voltage << 8;
                        Voltage |= dtmp[4];

                        Current = dtmp[5];
                        Current = Current << 8;
                        Current |= dtmp[6];

                        Power = (Voltage * Current) / 10.0f;
                        ESP_LOGI(TAG, "电能数据: %dV, %.1fA, %.1fW", Voltage, Current / 10.0f, Power);
                    } else if (event.size == 9) {
                        Hum = dtmp[3];
                        Hum = Hum << 8;
                        Hum |= dtmp[4];
                        
                        Tem = dtmp[5];
                        Tem = Tem << 8;
                        Tem |= dtmp[6];
                        
                        ESP_LOGI(TAG, "温湿度数据: %.1f°C, %.1f%%", Tem / 10.0f, Hum / 10.0f);
                    }
                    break;
                    
                case UART_FIFO_OVF:
                    ESP_LOGW(TAG, "UART FIFO溢出");
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                    
                case UART_BUFFER_FULL:
                    ESP_LOGW(TAG, "UART缓冲区满");
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                    
                case UART_BREAK:
                    ESP_LOGW(TAG, "UART线路断开");
                    break;
                    
                case UART_FRAME_ERR:
                    ESP_LOGW(TAG, "UART帧错误");
                    break;
                    
                default:
                    ESP_LOGW(TAG, "未知UART事件: %d", event.type);
                    break;
            }
        }
    }
    
    free(dtmp);
    vTaskDelete(NULL);
}

/* 串口发送任务 */
void uart_T_task(void *p) {
    while (1) {
        uart_write_bytes(EX_UART_NUM, get_jsy_value, 8);
        vTaskDelay(pdMS_TO_TICKS(300));
        uart_write_bytes(EX_UART_NUM, get_val, 8);
        vTaskDelay(pdMS_TO_TICKS(300));
    }
}

/* WiFi事件处理 */
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                              int32_t event_id, void* event_data) {
    if (event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        ESP_LOGI(TAG, "设备连接: "MACSTR", AID=%d", MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        ESP_LOGI(TAG, "设备断开: "MACSTR", AID=%d, 原因=%d", MAC2STR(event->mac), event->aid, event->reason);
    }
}

/* 初始化WiFi AP */
void wifi_init_softap(void) {
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_ap();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));

    wifi_config_t wifi_config = {
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
            .channel = EXAMPLE_ESP_WIFI_CHANNEL,
            .password = EXAMPLE_ESP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_STA_CONN,
            .authmode = WIFI_AUTH_WPA2_PSK,
            .pmf_cfg = {
                .required = true,
            },
        },
    };
    
    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }
    
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "WiFi AP启动完成. SSID:%s 密码:%s 信道:%d",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}

/* HTTP请求处理函数:处理根路径"/"的GET请求,返回带实时数据的HTML页面 */
static esp_err_t root_get_handler(httpd_req_t *req) {
    // 分配内存存储HTML内容(长度为模板长度+200,预留数据填充空间)
    char *html_content = (char *)malloc(strlen(HTML_PAGE) + 200);
    if (!html_content) {// 若内存分配失败
        httpd_resp_send_500(req);// 发送500(服务器内部错误)响应
        return ESP_FAIL; // 返回失败
    }
    
    // 格式化HTML内容,将实时数据填充到HTML代码模板的占位符中
    snprintf(html_content, strlen(HTML_PAGE) + 200, HTML_PAGE, 
             Tem / 10.0f, // 温度(实际值 = 存储值/10)
             Hum / 10.0f,// 湿度(实际值 = 存储值/10)
             Voltage,// 电压
             Current / 10.0f, // 电流(实际值 = 存储值/10)
             Power,// 功率
             get_current_time());// 返回最后更新时间(字符串)
    
    // 发送HTTP响应
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, html_content, strlen(html_content));
    
    free(html_content); // 释放内存
    return ESP_OK;
}

/* HTTP服务器URI配置:定义根路径"/"的处理规则 */
static httpd_uri_t root = {
    .uri       = "/",// 匹配的URI路径
    .method    = HTTP_GET,// 支持的HTTP方法(GET)
    .handler   = root_get_handler,//GET方法的 处理函数
    .user_ctx  = NULL           // 用户上下文数据(无)
};

/* 启动HTTP服务器 */
static httpd_handle_t start_webserver(void) {
    httpd_handle_t server = NULL;       // 服务器句柄
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();// 默认服务器配置
    config.lru_purge_enable = true; // 启用LRU(最近最少使用)缓存清理

    // 启动HTTP服务器
    if (httpd_start(&server, &config) == ESP_OK) {

        // 注册根路径"/"的处理函数
        httpd_register_uri_handler(server, &root);
        ESP_LOGI(TAG, "HTTP服务器已启动,端口: %d", config.server_port);
        return server;
    }

    ESP_LOGE(TAG, "HTTP服务器启动失败!");
    return NULL;
}

void app_main(void) {
    // 初始化NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    // 初始化UART
    uart_config_t uart_config = {
        .baud_rate = 9600,
        .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,
    };
    
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
    uart_param_config(EX_UART_NUM, &uart_config);
    uart_set_pin(EX_UART_NUM, GPIO_NUM_4, GPIO_NUM_5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    // 创建任务
    xTaskCreate(uart_event_task, "uart_event_task", 4046, NULL, 12, NULL);
    xTaskCreate(uart_T_task, "uart_T_task", 4046, NULL, 10, NULL);

    // 初始化时间
    setenv("TZ", "CST-8", 1);
    tzset();
    
    // 初始化WiFi和HTTP服务器
    ESP_LOGI(TAG, "初始化WiFi AP...");
    wifi_init_softap();
    
    ESP_LOGI(TAG, "启动HTTP服务器...");
    httpd_handle_t server = start_webserver();
    
    ESP_LOGI(TAG, "系统已启动完成");
    ESP_LOGI(TAG, "请连接热点: %s", EXAMPLE_ESP_WIFI_SSID);
    ESP_LOGI(TAG, "然后在浏览器访问: http://192.168.4.1");
}

上述代码时间显示有问题,下面是优化后的代码 显示时间为手机的时间与esp32无关


#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include <esp_http_server.h>
#include <stdio.h>
#include <string.h>
#include "freertos/queue.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "cJSON.h"
#include <time.h>
#include "esp_sntp.h"

/* 配置参数 */
#define EXAMPLE_ESP_WIFI_SSID "laotie666"
#define EXAMPLE_ESP_WIFI_PASS "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL 1
#define EXAMPLE_MAX_STA_CONN 4
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)

#define EX_UART_NUM UART_NUM_1
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)

/* 全局变量 */
uint8_t get_jsy_value[8] = {0x02, 0x03, 0x00, 0x48, 0x00, 0x05, 0x05, 0xEC};
uint8_t get_val[8] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B};
uint16_t Hum = 255; // 湿度值 Hum = 实际值 * 10
int16_t Tem = 232;  // 温度值 Tem = 实际值 * 10
uint16_t Voltage = 24, Current = 2;
float Power = 2.3; // 功率

static QueueHandle_t uart0_queue;
static const char *TAG = "wifi softAP";

/* 美观的HTML页面模板 */
static const char *HTML_PAGE = R"rawliteral(
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ESP32 环境监测</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        
        .container {
            background: rgba(255, 255, 255, 0.15);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            width: 100%;
            max-width: 500px;
            padding: 30px;
            color: white;
        }
        
        header {
            text-align: center;
            margin-bottom: 30px;
        }
        
        h1 {
            font-size: 28px;
            margin-bottom: 10px;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
        }
        
        .status {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            font-size: 16px;
        }
        
        .status-indicator {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background-color: #4CAF50;
            box-shadow: 0 0 10px #4CAF50;
        }
        
        .sensors-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }
        
        .sensor-card {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 15px;
            padding: 20px;
            text-align: center;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            cursor: pointer;
        }
        
        .sensor-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
            background: rgba(255, 255, 255, 0.2);
        }
        
        .sensor-icon {
            font-size: 40px;
            margin-bottom: 15px;
        }
        
        .sensor-value {
            font-size: 32px;
            font-weight: bold;
            margin: 10px 0;
        }
        
        .sensor-unit {
            font-size: 16px;
            opacity: 0.8;
        }
        
        .sensor-title {
            font-size: 18px;
            margin-bottom: 10px;
            color: #FFD700;
        }
        
        .power-section {
            background: rgba(0, 0, 0, 0.2);
            border-radius: 15px;
            padding: 20px;
            margin-bottom: 25px;
        }
        
        .power-title {
            text-align: center;
            font-size: 20px;
            margin-bottom: 15px;
            color: #FFD700;
        }
        
        .power-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 15px;
        }
        
        .power-card {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 10px;
            padding: 15px;
            text-align: center;
        }
        
        .power-value {
            font-size: 24px;
            font-weight: bold;
            margin: 5px 0;
        }
        
        .power-label {
            font-size: 14px;
            opacity: 0.8;
        }


    .last-update {
        font-size: 16px;
        margin-bottom: 8px;
        color: #FFD700;
    }



    #current-time {
        text-align: center;
            font-size: 14px;
            margin-top: 10px;
            opacity: 0.7;
    }
        
        .refresh-info {
            text-align: center;
            font-size: 14px;
            margin-top: 10px;
            opacity: 0.7;
        }
        
        footer {
            text-align: center;
            margin-top: 30px;
            font-size: 14px;
            opacity: 0.8;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>ESP32 环境监测</h1>
            <div class="status">
                <div class="status-indicator"></div>
                <span>设备在线</span>
            </div>
        </header>
        
        <div class="sensors-grid">
            <div class="sensor-card" style="border: 2px solid #FF5252;">
                <div class="sensor-icon">🌡️</div>
                <div class="sensor-title">温度</div>
                <div class="sensor-value">%.1f</div>
                <div class="sensor-unit">°C</div>
            </div>
            
            <div class="sensor-card" style="border: 2px solid #29B6F6;">
                <div class="sensor-icon">💧</div>
                <div class="sensor-title">湿度</div>
                <div class="sensor-value">%.1f</div>
                <div class="sensor-unit">%%</div>
            </div>
        </div>
        
        <div class="power-section">
            <div class="power-title">电能参数</div>
            <div class="power-grid">
                <div class="power-card">
                    <div class="power-label">电压</div>
                    <div class="power-value">%d</div>
                    <div class="power-unit">V</div>
                </div>
                
                <div class="power-card">
                    <div class="power-label">电流</div>
                    <div class="power-value">%.1f</div>
                    <div class="power-unit">A</div>
                </div>
                
                <div class="power-card">
                    <div class="power-label">功率</div>
                    <div class="power-value">%.1f</div>
                    <div class="power-unit">W</div>
                </div>
            </div>
        </div>
        
        
        <div class="refresh-info">数据更新时间: <span id="current-time">正在获取...</span></div>

        <div class="refresh-info">页面每秒自动刷新</div>
        
        <footer>
            ESP32 环境监测系统 | © 2025
        </footer>
    </div>
    
    <script>
function updateSystemTime() {
    const now = new Date();
    const timeString = now.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        hour12: false
    });
    document.getElementById('current-time').textContent = timeString;
}
        updateSystemTime();

        setInterval(updateSystemTime, 1000);
        setTimeout(function() {
            location.reload();
        }, 1000);
    </script>
</body>
</html>
)rawliteral";



/* UART事件处理任务 */
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 (;;)
    {
        if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY))
        {
            bzero(dtmp, RD_BUF_SIZE);

            switch (event.type)
            {
            case UART_DATA:
                uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);

                if (event.size == 15)
                {
                    Voltage = dtmp[3];
                    Voltage = Voltage << 8;
                    Voltage |= dtmp[4];

                    Current = dtmp[5];
                    Current = Current << 8;
                    Current |= dtmp[6];

                    Power = (Voltage * Current) / 10.0f;
                    ESP_LOGI(TAG, "电能数据: %dV, %.1fA, %.1fW", Voltage, Current / 10.0f, Power);
                }
                else if (event.size == 9)
                {
                    Hum = dtmp[3];
                    Hum = Hum << 8;
                    Hum |= dtmp[4];

                    Tem = dtmp[5];
                    Tem = Tem << 8;
                    Tem |= dtmp[6];

                    ESP_LOGI(TAG, "温湿度数据: %.1f°C, %.1f%%", Tem / 10.0f, Hum / 10.0f);
                }
                break;

            case UART_FIFO_OVF:
                ESP_LOGW(TAG, "UART FIFO溢出");
                uart_flush_input(EX_UART_NUM);
                xQueueReset(uart0_queue);
                break;

            case UART_BUFFER_FULL:
                ESP_LOGW(TAG, "UART缓冲区满");
                uart_flush_input(EX_UART_NUM);
                xQueueReset(uart0_queue);
                break;

            case UART_BREAK:
                ESP_LOGW(TAG, "UART线路断开");
                break;

            case UART_FRAME_ERR:
                ESP_LOGW(TAG, "UART帧错误");
                break;

            default:
                ESP_LOGW(TAG, "未知UART事件: %d", event.type);
                break;
            }
        }
    }

    free(dtmp);
    vTaskDelete(NULL);
}

/* 串口发送任务 */
void uart_T_task(void *p)
{
    while (1)
    {
        uart_write_bytes(EX_UART_NUM, get_jsy_value, 8);
        vTaskDelay(pdMS_TO_TICKS(300));
        uart_write_bytes(EX_UART_NUM, get_val, 8);
        vTaskDelay(pdMS_TO_TICKS(300));
    }
}

/* WiFi事件处理 */
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
                               int32_t event_id, void *event_data)
{
    if (event_id == WIFI_EVENT_AP_STACONNECTED)
    {
        wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
        ESP_LOGI(TAG, "设备连接: " MACSTR ", AID=%d", MAC2STR(event->mac), event->aid);
    }
    else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
    {
        wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
        ESP_LOGI(TAG, "设备断开: " MACSTR ", AID=%d, 原因=%d", MAC2STR(event->mac), event->aid, event->reason);
    }
}

/* 初始化WiFi AP */
void wifi_init_softap(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_ap();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));

    wifi_config_t wifi_config = {
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
            .channel = EXAMPLE_ESP_WIFI_CHANNEL,
            .password = EXAMPLE_ESP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_STA_CONN,
            .authmode = WIFI_AUTH_WPA2_PSK,
            .pmf_cfg = {
                .required = true,
            },
        },
    };

    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0)
    {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "WiFi AP启动完成. SSID:%s 密码:%s 信道:%d",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}

/* HTTP请求处理函数:处理根路径"/"的GET请求,返回带实时数据的HTML页面 */
static esp_err_t root_get_handler(httpd_req_t *req)
{
    // 分配内存存储HTML内容(长度为模板长度+200,预留数据填充空间)
    char *html_content = (char *)malloc(strlen(HTML_PAGE) + 200);
    if (!html_content)
    {                             // 若内存分配失败
        httpd_resp_send_500(req); // 发送500(服务器内部错误)响应
        return ESP_FAIL;          // 返回失败
    }

    // 格式化HTML内容,将实时数据填充到HTML代码模板的占位符中
    snprintf(html_content, strlen(HTML_PAGE) + 200, HTML_PAGE,
             Tem / 10.0f,         // 温度(实际值 = 存储值/10)
             Hum / 10.0f,         // 湿度(实际值 = 存储值/10)
             Voltage,             // 电压
             Current / 10.0f,     // 电流(实际值 = 存储值/10)
             Power);              // 功率

    // 发送HTTP响应
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, html_content, strlen(html_content));

    free(html_content); // 释放内存
    return ESP_OK;
}

/* HTTP服务器URI配置:定义根路径"/"的处理规则 */
static httpd_uri_t root = {
    .uri = "/",                  // 匹配的URI路径
    .method = HTTP_GET,          // 支持的HTTP方法(GET)
    .handler = root_get_handler, // GET方法的 处理函数
    .user_ctx = NULL             // 用户上下文数据(无)
};

/* 启动HTTP服务器 */
static httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;                   // 服务器句柄
    httpd_config_t config = HTTPD_DEFAULT_CONFIG(); // 默认服务器配置
    config.lru_purge_enable = true;                 // 启用LRU(最近最少使用)缓存清理

    // 启动HTTP服务器
    if (httpd_start(&server, &config) == ESP_OK)
    {

        // 注册根路径"/"的处理函数
        httpd_register_uri_handler(server, &root);
        ESP_LOGI(TAG, "HTTP服务器已启动,端口: %d", config.server_port);
        return server;
    }

    ESP_LOGE(TAG, "HTTP服务器启动失败!");
    return NULL;
}

void app_main(void)
{
    // 初始化NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    // 初始化UART
    uart_config_t uart_config = {
        .baud_rate = 9600,
        .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,
    };

    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
    uart_param_config(EX_UART_NUM, &uart_config);
    uart_set_pin(EX_UART_NUM, GPIO_NUM_4, GPIO_NUM_5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    // 创建任务
    xTaskCreate(uart_event_task, "uart_event_task", 4046, NULL, 12, NULL);
    xTaskCreate(uart_T_task, "uart_T_task", 4046, NULL, 10, NULL);

    // 初始化时间
    setenv("TZ", "CST-8", 1);
    tzset(); // 应用时区设置

    // 初始化WiFi和HTTP服务器
    ESP_LOGI(TAG, "初始化WiFi AP...");
    wifi_init_softap();

    ESP_LOGI(TAG, "启动HTTP服务器...");
    httpd_handle_t server = start_webserver();

    ESP_LOGI(TAG, "系统已启动完成");
    ESP_LOGI(TAG, "请连接热点: %s", EXAMPLE_ESP_WIFI_SSID);
    ESP_LOGI(TAG, "然后在浏览器访问: http://192.168.4.1");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值