ESP32(八) 简单的webserver
#include <esp_wifi.h>
#include <nvs.h>
#include <sys/param.h>
#include "esp_mac.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_http_server.h"
#include "cJSON.h"
#include "web_server.h"
#include "nvs_wificfg.h"
#include "rainmaker_task.h"
#define MAX_FILE_SIZE (200*1024)
static const char *TAG = "web_server";
esp_event_handler_instance_t sta_instance_got_ip;
esp_event_handler_instance_t sta_instance_any_id;
esp_event_handler_instance_t ap_instance_any_id;
static esp_err_t post_wifi_handler(httpd_req_t *req) {
char buf[128];
int ret, remaining = req->content_len;
bzero(buf, sizeof(buf));
/*
* [ycp]: 接收 POST 数据
*/
while (remaining > 0) {
ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)));
if (ret <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
continue;
}
httpd_resp_sendstr(req, "Failed to receive data");
return ESP_FAIL;
}
remaining -= ret;
}
/*
* [ycp]: 解析网页操作传入的 CJSON
*/
cJSON *root = cJSON_Parse(buf);
if (root == NULL) {
httpd_resp_sendstr(req, "Failed to parse JSON data");
return ESP_FAIL;
}
char *ssid = cJSON_GetObjectItem(root, "wifi_ssid")->valuestring;
char *passwd = cJSON_GetObjectItem(root, "wifi_passwd")->valuestring;
extern nvs_handle_t my_handle;
nvsset_wificfg((const uint8_t*)"WiFi_NVS",&my_handle,(uint8_t*)ssid,(uint8_t*)passwd);
cJSON_Delete(root);
httpd_resp_sendstr(req, "WiFi configuration successful");
return ESP_OK;
}
/*
* [ycp]: 主页的 GET
*/
static esp_err_t root_get_handler(httpd_req_t *req) {
extern const unsigned char upload_script_start[] asm("_binary_upload_script_html_start");
extern const unsigned char upload_script_end[] asm("_binary_upload_script_html_end");
const size_t upload_script_size = (upload_script_end - upload_script_start);
httpd_resp_send(req, (const char *) upload_script_start, upload_script_size);
return ESP_OK;
}
httpd_handle_t server = NULL;
esp_err_t start_web_server() {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
ESP_LOGI(TAG, "Starting HTTP Server");
if (httpd_start(&server, &config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start file server!");
return ESP_FAIL;
} else{
ESP_LOGI(TAG, "start file server ok!");
}
httpd_uri_t wifi_data = {
.uri = "/wifi_data",
.method = HTTP_POST,
.handler = post_wifi_handler,
.user_ctx = NULL
};
httpd_register_uri_handler(server, &wifi_data);
httpd_uri_t root = {
.uri = "/",
.method = HTTP_GET,
.handler = root_get_handler,
.user_ctx = NULL
};
httpd_register_uri_handler(server, &root);
return ESP_OK;
}
#define EXAMPLE_ESP_WIFI_SSID "ycp666"
#define EXAMPLE_ESP_WIFI_PASS "88888888"
#define EXAMPLE_ESP_WIFI_CHANNEL 1
#define EXAMPLE_MAX_STA_CONN 4
#define EXAMPLE_ESP_MAXIMUM_RETRY 2
static int s_retry_num = 0;
static EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
/*
* [ycp]: 连接断开回调,仅用于 LOG
*/
static void ap_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, "station "MACSTR" join, 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, "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
}
/*
* [ycp]: WIFI 回调事件,用于执行 WIFI 的操作
*/
static void sta_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG, "connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
// 完整的反初始化 WiFi 相关资源,讲究顺序的
void wifi_uninit(uint8_t if_ap) {
esp_wifi_stop();
}
void wifi_init_softap(void) {
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,
&ap_event_handler,
NULL,
ap_instance_any_id));
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_WPA_WPA2_PSK
},
};
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_init_softap finished. SSID:%s password:%s channel:%d",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
int8_t wifi_init_sta(uint8_t wifi_ssid[],uint8_t wifi_passwd[]) {
s_wifi_event_group = xEventGroupCreate();
esp_netif_create_default_wifi_sta();
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,
&sta_event_handler,
NULL,
&sta_instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&sta_event_handler,
NULL,
&sta_instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
//.ssid = wifi_ssid,
//.password = wifi_password,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
memcpy(wifi_config.sta.ssid, wifi_ssid, 20);
memcpy(wifi_config.sta.password, wifi_passwd, 20);
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());
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
wifi_ssid, wifi_passwd);
//rainmaker_init();
return 0;
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
wifi_ssid, wifi_passwd);
return -1;
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
return -1;
}
}
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WiFi 密码配置</title>
<style>
.form-container {
max-width: 500px;
margin: 0 auto;
padding: 2rem;
border: 1px solid #ccc;
border-radius: 10px;
}
label, input {
display: block;
margin-bottom: 1rem;
}
@media (max-width: 600px) {
.form-container {
padding: 1rem;
}
}
</style>
</head>
<body>
<div class="form_container">
<h3>WiFi 密码配置</h3>
<form>
<label for="wifi_ssid">WiFi 名称</label>
<input type="text" id="wifi_ssid" name="wifi_ssid" placeholder="ssid">
<label for="wifi_password">密码</label>
<input type="password" id="wifi_password" name="wifi_password" placeholder="password">
<button id="send_wifi" type="button" onclick="send_wifi_data()">提交</button>
<button id="clear_input" type="button" onclick="clear_button()">清除</button>
</form>
</div>
<script>
function send_wifi_data() {
var wifi_ssid = document.getElementById("wifi_ssid").value;
var wifi_password = document.getElementById("wifi_password").value;
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "/wifi_data", true);
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4) {
if (xhttp.status == 200) {
console.log(xhttp.responseText);
alert(xhttp.responseText);
} else if (xhttp.status == 0) {
alert("Server closed the connection abruptly!");
} else {
alert(xhttp.status + " Error!\n" + xhttp.responseText);
}
}
};
var data = {
"wifi_ssid": wifi_ssid,
"wifi_passwd": wifi_password
}
xhttp.send(JSON.stringify(data));
}
function clear_button() {
document.getElementById("wifi_ssid").value = '';
document.getElementById("wifi_password").value = '';
}
</script>
</body>
</html>
License:
CC BY 4.0