ESP8266學習筆記(20)——HTTP服務器(RTOS SDK)

一彤路、背景

首先手機APP連接智能插座熱點(AP)將網(wǎng)關的SSID和密碼通過HTTP協(xié)議配置到插座徒恋,完成配置后智能插座連接網(wǎng)關兵拢。

Post請求和Get請求:

二介褥、API說明

以下軟件定時器接口位于 esp_http_server/include/esp_http_server.h

2.1 httpd_start

2.2 httpd_register_uri_handler

通過傳遞類型httpd_uri_t結構的對象來注冊URI處理程序曲聂,該對象具有包括uri名稱霹购,method類型(例如,HTTPD_GET/HTTPD_POST/HTTPD_PUT等等)朋腋,類型的函數(shù)指針和指向用戶上下文數(shù)據(jù)的指針的成員齐疙。esp_err_t *handler (httpd_req_t *req) user_ctx

2.3 httpd_req_get_url_query_len

2.4 httpd_req_get_url_query_str

2.5 httpd_req_recv

2.6 httpd_resp_set_status

2.7 httpd_resp_send

三、移植文件

百度網(wǎng)盤:https://pan.baidu.com/s/1ku_qiKOEuOdLBcNbswL7WQ[https://pan.baidu.com/s/1ku_qiKOEuOdLBcNbswL7WQ] 提取碼:490n

3.1 user_http_server.c

/*********************************************************************
 * INCLUDES
 */
#include <sys/param.h>

#include "esp_http_server.h"
#include "esp_timer.h"
#include "cJSON.h"
#include "esp_err.h"
#include "esp_log.h"

#include "user_http_server.h"
#include "user_wifi.h"
#include "common.h"

static esp_err_t handleGetUrlPath(httpd_req_t *pRequest);
static esp_err_t handlePostUrlPath(httpd_req_t *pRequest);
static esp_err_t findRequestData(char *pRequestData);
static void queryClientInfo(void);
static void configWifi(char *pRequestData);
static void configCloudServer(char *pRequestData);
static void configBleInit(char *pRequestData);
static void sendGetResponse(bool responseOk, char *pResponseData);
static void sendPostResponse(bool responseOk, char *pResponseData);
static void jsonPackageResponseData(bool responseOk, char *pSendData);
static void jsonPackageClientInfoData(bool responseOk, char *pSendData);
static void startDelayHandleTimer(void);
static void delayHandleTimerCallback(void *arg);

/*********************************************************************
 * LOCAL VARIABLES
 */
static httpd_req_t *s_pRequest = NULL;

static httpd_uri_t s_uriClientGet = 
{
    .uri       = "/client",
    .method    = HTTP_GET,
    .handler   = handleGetUrlPath,
    .user_ctx  = NULL
};

static httpd_uri_t s_uriConfigPost = 
{
    .uri       = "/config",
    .method    = HTTP_POST,
    .handler   = handlePostUrlPath,
    .user_ctx  = NULL
};

// 延遲處理定時器旭咽,確闭攴埽可以回復響應成功
esp_timer_handle_t s_delayHandleTimer = 0;
esp_timer_create_args_t s_delayHandleTimerArg = 
{ 
    .callback = &delayHandleTimerCallback,                                              // 設置回調(diào)函數(shù)
    .arg = NULL,                                                                        // 不攜帶參數(shù)
    .name = "DelayHandleTimer"                                                          // 定時器名字
};

char s_configSsid[SSID_MAX_LEN] = {0};
char s_configPassword[PASSWORD_MAX_LEN] = {0};

static const char *TAG = "user_http_server";

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief HTTP服務器初始化
 @param 無
 @return 無
*/
httpd_handle_t HttpServerInit(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    // 啟動HTTP服務器
    ESP_LOGI(TAG, "Starting HTTP server on port: '%d'", config.server_port);
    if(httpd_start(&server, &config) == ESP_OK)                                              
    {
        // 注冊URI處理程序
        httpd_register_uri_handler(server, &s_uriConfigPost);
        httpd_register_uri_handler(server, &s_uriClientGet);
        return server;
    }

    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}


/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief HTTP GET請求URL處理
 @param pRequest -[in] HTTP請求結構體
 @return 錯誤碼
*/
static esp_err_t handleGetUrlPath(httpd_req_t *pRequest)
{
    esp_err_t result = ESP_FAIL;
    char *pBuffer;
    size_t bufferLength;

    /* Read URL query string length and allocate memory for length + 1,
     * extra byte for null termination */
    bufferLength = httpd_req_get_url_query_len(pRequest) + 1;
    if(bufferLength > 1) 
    {
        pBuffer = malloc(bufferLength);
        if(httpd_req_get_url_query_str(pRequest, pBuffer, bufferLength) == ESP_OK) 
        {
            ESP_LOGI(TAG, "Found URL query => %s", pBuffer);
            s_pRequest = pRequest;
            char requestData[REQUEST_DATA_SIZE] = {0};
            result = findRequestData(requestData);

            if(strcmp(pBuffer, "command=info") == 0)
            {
                queryClientInfo();
            }
        }
        free(pBuffer);
    }
    return result;
}

/**
 @brief HTTP POST請求URL處理
 @param pRequest -[in] HTTP請求結構體
 @return 錯誤碼
*/
static esp_err_t handlePostUrlPath(httpd_req_t *pRequest)
{
    esp_err_t result = ESP_FAIL;
    char *pBuffer;
    size_t bufferLength;

    /* Read URL query string length and allocate memory for length + 1,
     * extra byte for null termination */
    bufferLength = httpd_req_get_url_query_len(pRequest) + 1;
    if(bufferLength > 1) 
    {
        pBuffer = malloc(bufferLength);
        if(httpd_req_get_url_query_str(pRequest, pBuffer, bufferLength) == ESP_OK) 
        {
            ESP_LOGI(TAG, "Found URL query => %s", pBuffer);
            s_pRequest = pRequest;
            char requestData[REQUEST_DATA_SIZE] = {0};
            result = findRequestData(requestData);

            if(strcmp(pBuffer, "command=wifi") == 0)
            {
                configWifi(requestData);
            }
            else if(strcmp(pBuffer, "command=cloud_server") == 0)
            {
                configCloudServer(requestData);                 
            }
            else if(strcmp(pBuffer, "command=switch") == 0)
            {
                
            }
            else if(strcmp(pBuffer, "command=ble_cmd") == 0)
            {
                
            }
            else if(strcmp(pBuffer, "command=ble_init") == 0)
            {
                configBleInit(requestData);     
            }
        }
        free(pBuffer);
    }
    return result;
}

/**
 @brief 查找請求數(shù)據(jù)
 @param pRequestData -[out] 請求的數(shù)據(jù)
 @return 錯誤碼
*/
static esp_err_t findRequestData(char *pRequestData)
{
    int result, remaining = s_pRequest->content_len;

    while(remaining > 0) 
    {
        // 從HTTP請求讀取內(nèi)容數(shù)據(jù)
        if((result = httpd_req_recv(s_pRequest, pRequestData, MIN(remaining, REQUEST_DATA_SIZE))) <= 0) 
        {
            if(result == HTTPD_SOCK_ERR_TIMEOUT) 
            {
                // 發(fā)生超時,繼續(xù)接收
                continue;
            }
            return ESP_FAIL;
        }
        remaining -= result;

        /* Log data received */
        ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
        ESP_LOGI(TAG, "%.*s", result, pRequestData);
        ESP_LOGI(TAG, "====================================");
    }
    return ESP_OK;
}

/**
 @brief 查詢終端信息接口
 @param pRequestData -[in] 請求的數(shù)據(jù)
 @return 無
*/
static void queryClientInfo(void)
{
    char sendData[RESPONSE_DATA_SIZE] = {0};
    jsonPackageClientInfoData(true, sendData);
    sendGetResponse(true, sendData);
}

/**
 @brief 配置WIFI接口
 @param pRequestData -[in] 請求的數(shù)據(jù)
 @return 無
*/
static void configWifi(char *pRequestData)
{
    cJSON *pRoot = cJSON_Parse(pRequestData);
    if(!pRoot)
    {
        return ;
    }
   
    char sendData[RESPONSE_DATA_SIZE] = {0};
    cJSON *pRequest = cJSON_GetObjectItem(pRoot, "request");                            // 解析request字段內(nèi)容
    if(!pRequest)
    {
        sprintf(sendData, "%s", "No request Item");
        sendPostResponse(false, sendData);
        cJSON_Delete(pRoot);
        return ;
    }

    cJSON *pStation = cJSON_GetObjectItem(pRequest, "station");                         // 解析request子節(jié)點station字段內(nèi)容
    cJSON *pSoftAp = cJSON_GetObjectItem(pRequest, "softap");                           // 解析request子節(jié)點softap字段內(nèi)容
    if(pStation)
    {
        cJSON *pSsid = cJSON_GetObjectItem(pStation, "ssid");
        cJSON *pPassword = cJSON_GetObjectItem(pStation, "password");
        if(!pSsid)
        {
            sprintf(sendData, "%s", "No ssid Item");
            sendPostResponse(false, sendData);
            cJSON_Delete(pRoot);
            return ;
        }
        if(!pPassword)
        {
            sprintf(sendData, "%s", "No password Item");
            sendPostResponse(false, sendData);
            cJSON_Delete(pRoot);
            return ;
        }

        strcpy(s_configSsid, pSsid->valuestring);
        strcpy(s_configPassword, pPassword->valuestring);

        sprintf(sendData, "%s", "Config station succeed");
        sendPostResponse(true, sendData);

        startDelayHandleTimer();

        // SetDhcpClientFlag(0);
        // ConfigStationMode(ssid, password);                                          // 配置連接路由器

        // UdpSendDeviceInfo();                                                     // UDP發(fā)送設備信息
        // EspPlatformCheckIp();                                                        // ESP平臺檢查IP
    }
    else if(pSoftAp)
    {
    }
    else
    {
        sprintf(sendData, "%s", "No station or softap Item");
        sendPostResponse(false, sendData);
    }

    cJSON_Delete(pRoot);
}

/**
 @brief 配置云服務器接口
 @param pRequestData -[in] 請求的數(shù)據(jù)
 @return 無
*/
static void configCloudServer(char *pRequestData)
{
    cJSON *pRoot = cJSON_Parse(pRequestData);
    if(!pRoot)
    {
        return ;
    }

    char sendData[RESPONSE_DATA_SIZE] = {0};
    cJSON *pRequest = cJSON_GetObjectItem(pRoot, "request");                            // 解析request字段內(nèi)容
    if(!pRequest)
    {
        sprintf(sendData, "%s", "No request Item");
        sendPostResponse(false, sendData);
        cJSON_Delete(pRoot);
        return ;
    }

    cJSON *pTcp = cJSON_GetObjectItem(pRequest, "tcp");                                 // 解析request子節(jié)點tcp字段內(nèi)容
    cJSON *pHttp = cJSON_GetObjectItem(pRequest, "http");                               // 解析request子節(jié)點http字段內(nèi)容

    if(pTcp)
    {
        char token[64] = {0};

        cJSON *pIpAddr = cJSON_GetObjectItem(pTcp, "ip");
        cJSON *pPort = cJSON_GetObjectItem(pTcp, "port");
        cJSON *pDomain = cJSON_GetObjectItem(pTcp, "domain");
        cJSON *pToken = cJSON_GetObjectItem(pTcp, "token");
        if(pIpAddr)
        {
            char ip[16] = {0};
            strcpy(ip, pIpAddr->valuestring);
            // g_tcpCloudServerUrl.ip.addr = ipaddr_addr(ip);                              // 點分十進制寫入IP結構體
        }
        if(pPort)
        {
            // g_tcpCloudServerUrl.port = pPort->valueint;
        }
        if(pDomain)
        {
            char domain[32] = {0};
            strcpy(domain, pDomain->valuestring);
            // memcpy(g_tcpCloudServerUrl.domain, domain, os_strlen(domain));
        }
        if(pToken)
        {
            strcpy(token, pToken->valuestring);
        }

        sprintf(sendData, "%s", "Config tcp cloud server succeed");
        sendPostResponse(true, sendData);

        // SaveTcpServerParam(&g_tcpCloudServerUrl);                                       // 保存TCP服務器參數(shù)到Flash
        // SetFirstConnectEspPlatformFlag(true);
        // EspPlatformCheckIp();                                                           // ESP平臺檢查IP
    }
    else if(pHttp)
    {
        char ip[16] = {0};

        cJSON *pIpAddr = cJSON_GetObjectItem(pHttp, "ip");
        cJSON *pPort = cJSON_GetObjectItem(pHttp, "port");
        cJSON *pDomain = cJSON_GetObjectItem(pHttp, "domain");
        cJSON *pPath = cJSON_GetObjectItem(pHttp, "path");
        if(pIpAddr)
        {
            strcpy(ip, pIpAddr->valuestring);
            // g_httpCloudServerUrl.ip.addr = ipaddr_addr(ip);                          // 點分十進制寫入IP結構體
        }
        if(pPort)
        {
            // g_httpCloudServerUrl.port = pPort->valueint;
        }
        if(pDomain)
        {
            // strcpy(g_httpCloudServerUrl.domain, pDomain->valuestring);
        }
        if(pPath)
        {
            // strcpy(g_httpCloudServerUrl.path, pPath->valuestring);
        }

        sprintf(sendData, "%s", "Config http cloud server succeed");
        sendPostResponse(true, sendData);

        // SaveHttpServerParam(&g_httpCloudServerUrl);                                     // 保存HTTP服務器參數(shù)到Flash
        // HttpCloudCheckIp();
    }
    else
    {
        sprintf(sendData, "%s", "No tcp or http Item");
        sendPostResponse(false, sendData);
    }

    cJSON_Delete(pRoot);
}

/**
 @brief 配置BLE初始化接口
 @param pRequestData -[in] 請求的數(shù)據(jù)
 @return 無
*/
static void configBleInit(char *pRequestData)
{
    cJSON *pRoot = cJSON_Parse(pRequestData);
    if(!pRoot)
    {
        return ;
    }

    char sendData[RESPONSE_DATA_SIZE] = {0};
    cJSON *pRequest = cJSON_GetObjectItem(pRoot, "request");                            // 解析request字段內(nèi)容
    if(!pRequest)
    {
        sprintf(sendData, "%s", "No request Item");
        sendPostResponse(false, sendData);
        cJSON_Delete(pRoot);
        return ;
    }

    cJSON *pBleInit = cJSON_GetObjectItem(pRequest, "ble_init");                        // 解析request子節(jié)點ble_init字段內(nèi)容
    cJSON *pBleSupervRssi = cJSON_GetObjectItem(pRequest, "ble_superv_rssi");           // 解析request子節(jié)點ble_superv_rssi字段內(nèi)容
    if(pBleInit)
    {
        char buffer[64] = {0};
        cJSON *pBleInitData = cJSON_GetObjectItem(pBleInit, "ble_init_data");

        if(pBleInitData)
        {
            strcpy(buffer, pBleInitData->valuestring);
            // UartSendLanBleInit(buffer);
        }
        else
        {
            sprintf(sendData, "%s", "No ble_init_data Item");
            sendPostResponse(false, sendData);
            cJSON_Delete(pRoot);
            return ;
        }

        sprintf(sendData, "%s", "Config ble init succeed");
        sendPostResponse(true, sendData);
    }
    else if(pBleSupervRssi)
    {
        cJSON *pRssi = cJSON_GetObjectItem(pBleSupervRssi, "rssi");

        if(pRssi)
        {
            // g_bleDeviceRssiStandrdValue = pRssi->valueint;
            // SaveBleDeviceRssiStandrdValue(g_bleDeviceRssiStandrdValue);
        }
        else
        {
            sprintf(sendData, "%s", "No rssi Item");
            sendPostResponse(false, sendData);
            cJSON_Delete(pRoot);
            return ;
        }

        sprintf(sendData, "%s", "Config ble superv rssi succeed");
        sendPostResponse(true, sendData);
    }
    else
    {
        sprintf(sendData, "%s", "No ble_init or ble_superv_rssi Item");
        sendPostResponse(false, sendData);
    }

    cJSON_Delete(pRoot);
}

/**
 @brief 發(fā)送GET請求HTTP響應
 @param responseOk -[in] 響應是否成功
 @param pResponseData -[in] 響應數(shù)據(jù)
 @return 無
*/
static void sendGetResponse(bool responseOk, char *pResponseData)
{
    if(responseOk)
    {
        httpd_resp_set_status(s_pRequest, HTTPD_200);                                   // 設置響應狀態(tài)200 OK
    }
    else
    {
        httpd_resp_set_status(s_pRequest, HTTPD_400);                                   // 設置響應狀態(tài)400 Bad Request
    }

    httpd_resp_send(s_pRequest, pResponseData, strlen(pResponseData));                  // 發(fā)送響應
}

/**
 @brief 發(fā)送POST請求的HTTP響應
 @param responseOk -[in] 響應是否成功
 @param pResponseData -[in] 響應數(shù)據(jù)
 @return 無
*/
static void sendPostResponse(bool responseOk, char *pResponseData)
{
    jsonPackageResponseData(responseOk, pResponseData);

    if(responseOk)
    {
        httpd_resp_set_status(s_pRequest, HTTPD_200);                                   // 設置響應狀態(tài)200 OK
    }
    else
    {
        httpd_resp_set_status(s_pRequest, HTTPD_400);                                   // 設置響應狀態(tài)400 Bad Request
    }

    httpd_resp_send(s_pRequest, pResponseData, strlen(pResponseData));                  // 發(fā)送響應
}

/**
 @brief JSON格式封裝響應數(shù)據(jù)
 @param responseOk -[in] 響應是否成功
 @param pSendData -[in&out] 要封裝的發(fā)送數(shù)據(jù)
 @return 無
*/
static void jsonPackageResponseData(bool responseOk, char *pSendData)
{
    cJSON *pRoot = cJSON_CreateObject();

    uint16 statusCode;

    if(responseOk)
    {
        statusCode = 200;
    }
    else
    {
        statusCode = 400;
    }

    cJSON_AddNumberToObject(pRoot, "status", statusCode);
    cJSON_AddStringToObject(pRoot, "message", pSendData);
    char *tempBuffer = cJSON_Print(pRoot);
    sprintf(pSendData, "%s", tempBuffer);

    free((void *) tempBuffer);
    cJSON_Delete(pRoot);
}

/**
 @brief JSON格式封裝終端信息數(shù)據(jù)
 @param responseOk -[in] 響應是否成功
 @param pSendData -[in&out] 要封裝的發(fā)送數(shù)據(jù)
 @return 無
*/
static void jsonPackageClientInfoData(bool responseOk, char *pSendData)
{
    cJSON *pRoot = cJSON_CreateObject();

    uint16 statusCode;

    if(responseOk)
    {
        statusCode = 200;
    }
    else
    {
        statusCode = 400;
    }

    char wifiMac[23] = {0};
    char bleMac[23] = {0};
    // GetWifiMacStr(wifiMac);
    // GetBleMacStr(bleMac);

    cJSON_AddNumberToObject(pRoot, "status", statusCode);
    cJSON_AddStringToObject(pRoot, "wifi_mac", "11:11:11:11:11:11");
    cJSON_AddStringToObject(pRoot, "ble_mac", "11:11:11:11:11:11");
    cJSON_AddStringToObject(pRoot, "ble_name", "a");
    cJSON_AddNumberToObject(pRoot, "ble_superv_rssi", 11);
    char *tempBuffer = cJSON_Print(pRoot);
    sprintf(pSendData, "%s", tempBuffer);

    free((void *) tempBuffer);
    cJSON_Delete(pRoot);
}

/**
 @brief 開啟延遲處理定時器
 @param 無
 @return 無
*/
static void startDelayHandleTimer(void) 
{
    // 開始創(chuàng)建一個單次周期的定時器并且執(zhí)行
    ESP_ERROR_CHECK(esp_timer_create(&s_delayHandleTimerArg, &s_delayHandleTimer));
    ESP_ERROR_CHECK(esp_timer_start_once(s_delayHandleTimer, DELAY_HANDLE_PERIOD));     // 1s                    
}

/**
 @brief 延遲處理定時器的回調(diào)函數(shù)
 @param 無
 @return 無
*/
static void delayHandleTimerCallback(void *arg) 
{
    ESP_LOGI(TAG, "delayHandleTimerCallback");

    ConfigStationMode(s_configSsid, s_configPassword);                                  // 配置連接路由器

    ESP_ERROR_CHECK(esp_timer_delete(s_delayHandleTimer));                              // 使用完后刪除定時器                              
}

/****************************************************END OF FILE****************************************************/

3.2 user_http_server.h

#ifndef _USER_HTTP_SERVER_H_
#define _USER_HTTP_SERVER_H_

/*********************************************************************
 * INCLUDES
 */
#include <esp_http_server.h>

/*********************************************************************
 * DEFINITIONS
 */
#define REQUEST_DATA_SIZE           512
#define RESPONSE_DATA_SIZE          256

#define DELAY_HANDLE_PERIOD         1000 * 1000         // 1s

/*********************************************************************
 * API FUNCTIONS
 */
httpd_handle_t HttpServerInit(void);

#endif /* _USER_HTTP_SERVER_H_ */

四穷绵、使用例子

cJSON使用部分查看 ESP8266學習筆記(8)——第三方庫cJSON使用
定時器使用部分查看 ESP8266學習筆記(19)——定時器接口使用(RTOS SDK)

4.1 初始化HTTP服務器

在main函數(shù)中調(diào)用HttpServerInit()

void app_main(void)
{
    printf("SDK version:%s\n", esp_get_idf_version());

    esp_timer_init();
    WifiInit();
    HttpServerInit();
}

在HttpServerInit()中啟動了HTTP服務器轿塔,并注冊了兩種URI處理程序

httpd_handle_t HttpServerInit(void)
{
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    // 啟動HTTP服務器
    ESP_LOGI(TAG, "Starting HTTP server on port: '%d'", config.server_port);
    if(httpd_start(&server, &config) == ESP_OK)                                              
    {
        // 注冊URI處理程序
        httpd_register_uri_handler(server, &s_uriConfigPost);
        httpd_register_uri_handler(server, &s_uriClientGet);
        return server;
    }

    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}

4.2 接收HTTP請求

使用Postman發(fā)送

POST /config?command=wifi HTTP/1.1
Host: 192.168.4.1:80
Cache-Control: no-cache

{ "request": { "station": { "ssid":"TP-LINK_576F", "password":"12345678" } } }

由于是Post請求,URI路徑為/config请垛,符合已注冊好的URI處理程序

static httpd_uri_t s_uriConfigPost = 
{
    .uri       = "/config",
    .method    = HTTP_POST,
    .handler   = handlePostUrlPath,
    .user_ctx  = NULL
};

于是進入handlePostUrlPath()進行處理催训,在handlePostUrlPath()中查找URL路徑洽议,找到command=wifi路徑宗收,進入配置WIFI處理函數(shù)configWifi()

static esp_err_t handlePostUrlPath(httpd_req_t *pRequest)
{
    esp_err_t result = ESP_FAIL;
    char *pBuffer;
    size_t bufferLength;

    /* Read URL query string length and allocate memory for length + 1,
     * extra byte for null termination */
    bufferLength = httpd_req_get_url_query_len(pRequest) + 1;
    if(bufferLength > 1) 
    {
        pBuffer = malloc(bufferLength);
        if(httpd_req_get_url_query_str(pRequest, pBuffer, bufferLength) == ESP_OK) 
        {
            ESP_LOGI(TAG, "Found URL query => %s", pBuffer);
            s_pRequest = pRequest;
            char requestData[REQUEST_DATA_SIZE] = {0};
            result = findRequestData(requestData);

            if(strcmp(pBuffer, "command=wifi") == 0)
            {
                configWifi(requestData);
            }
            else if(strcmp(pBuffer, "command=cloud_server") == 0)
            {
                configCloudServer(requestData);                 
            }
            else if(strcmp(pBuffer, "command=switch") == 0)
            {
                
            }
            else if(strcmp(pBuffer, "command=ble_cmd") == 0)
            {
                
            }
            else if(strcmp(pBuffer, "command=ble_init") == 0)
            {
                configBleInit(requestData);     
            }
        }
        free(pBuffer);
    }
    return result;
}

在configWifi()函數(shù)中對請求數(shù)據(jù)進行JSON解析,獲取SSID和密碼亚兄。
調(diào)用sendPostResponse進行響應回復混稽,隨后開啟定時器,1秒后進入配置WIFI連接路由器startDelayHandleTimer()


? 由 Leung 寫于 2020 年 4 月 27 日

? 參考:ESP-IDF編程指南 - HTTP服務器

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市匈勋,隨后出現(xiàn)的幾起案子礼旅,更是在濱河造成了極大的恐慌,老刑警劉巖洽洁,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痘系,死亡現(xiàn)場離奇詭異,居然都是意外死亡饿自,警方通過查閱死者的電腦和手機汰翠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昭雌,“玉大人复唤,你說我怎么就攤上這事≈蛭裕” “怎么了佛纫?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長总放。 經(jīng)常有香客問我呈宇,道長,這世上最難降的妖魔是什么局雄? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任攒盈,我火速辦了婚禮,結果婚禮上哎榴,老公的妹妹穿的比我還像新娘型豁。我一直安慰自己,他們只是感情好尚蝌,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布迎变。 她就那樣靜靜地躺著,像睡著了一般飘言。 火紅的嫁衣襯著肌膚如雪衣形。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天姿鸿,我揣著相機與錄音谆吴,去河邊找鬼。 笑死苛预,一個胖子當著我的面吹牛句狼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播热某,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼腻菇,長吁一口氣:“原來是場噩夢啊……” “哼胳螟!你這毒婦竟也來了?” 一聲冷哼從身側響起筹吐,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤糖耸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后丘薛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嘉竟,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年洋侨,在試婚紗的時候發(fā)現(xiàn)自己被綠了周拐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡凰兑,死狀恐怖妥粟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吏够,我是刑警寧澤勾给,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站锅知,受9級特大地震影響播急,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜售睹,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一桩警、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昌妹,春花似錦捶枢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至固歪,卻和暖如春蒜鸡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牢裳。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工逢防, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蒲讯。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓忘朝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親伶椿。 傳聞我的和親對象是個殘疾皇子辜伟,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容