ESP8266 WEB 配网 (基于 RTOSSDK 3.2)
一、效果二、基础例程HTTP服务基于examples\protocols\http_server\advanced_testsWIFI扫描基于https://github.com/espressif/esp-idf/tree/master/examples/wifi/scanAP配置基于ESP8266_RTOS_SDK\examples\wifi\getting_started\softAPDNS
一、效果
二、基础例程
- HTTP服务基于
examples\protocols\http_server\advanced_tests
- WIFI扫描基于https://github.com/espressif/esp-idf/tree/master/examples/wifi/scan
- AP配置基于
ESP8266_RTOS_SDK\examples\wifi\getting_started\softAP
- DNS服务基于https://github.com/ospanic/Captive_Portal_ESP
三、HTTPD配置
在返回一个URL页面时,会出现response uri/header too big
错误,这里需要设置一下接收页面的大小,通过make menuconfig来修改 成1500字节
Location: │
│ -> Component config
四、网页内嵌
通过 component.mk 可以将文件直接编译进固件里面,我这里内嵌了3个网页,都放在同级目录下
component.mk :
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_EMBED_TXTFILES := index.html
COMPONENT_EMBED_TXTFILES += WebConfig.html
COMPONENT_EMBED_TXTFILES += WiFiConfig.html
在程序里,可以这样调用:
extern const uint8_t index_html_start[] asm("_binary_index_html_start");
extern const uint8_t index_html_end[] asm("_binary_index_html_end");
extern const uint8_t WebConfig_html_start[] asm("_binary_WebConfig_html_start");
extern const uint8_t WebConfig_html_end[] asm("_binary_WebConfig_html_end");
extern const uint8_t WiFiConfig_html_start[] asm("_binary_WiFiConfig_html_start");
extern const uint8_t WiFiConfig_html_end[] asm("_binary_WiFiConfig_html_end");
五、认证页面跳转
苹果手机在连接WIFI后,会发起DNS请求,URL是/hotspot-detect.html
,将其转发到根地址即可,再对这个url进行一个GET请求的回复
///苹果跳转页面
{ .uri = "/hotspot-detect.html",
.method = HTTP_GET,
.handler = index_get_handler,
.user_ctx = NULL,
},
六、HTTPD回调配置
我这里主要做了3个网页
1.主页,有一个按钮,点击后会跳转到另外一个URL,我这里的逻辑是收到这个GET请求后,先进行WIFI扫描,将扫描结果,做成一个表格,和配置网页数据一起返回
2.配置网页,有2个框可以输入SSID和密码,下面有一个当前环境下的WIFI表这里可以做成下拉列表,用JS获取数据,这样就不会写错SSID了,这个暂时没实现
3.WIFI设置网页,显示正在链接WIFI中
回调的设置如下:
//主页
esp_err_t index_get_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "Free Stack for server task: '%u'", uxTaskGetStackHighWaterMark(NULL));
httpd_resp_send(req, (char *)&index_html_start, strlen((char *)&index_html_start));
return ESP_OK;
}
//配置页面
esp_err_t web_config_get_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "Free Stack for server task: '%u'", uxTaskGetStackHighWaterMark(NULL));
//httpd_resp_send(req, (char *)&WebConfig_html_start, strlen((char *)&WebConfig_html_start));
//先扫描wifi
char* buf = malloc(3000);
memset(buf,0,3000);
wifi_scan(buf);
printf("\r\nbuf=%s\r\n",buf);
// httpd_handle_t hd = resp_arg->hd;
// int fd = resp_arg->fd;
//resp_arg->hd = req->handle;
// resp_arg->fd = httpd_req_to_sockfd(req);
#define HTTPD_HDR_STR "HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html\r\n" \
"Content-Length: %d\r\n"
char head_buf[256];
memset(head_buf,0,sizeof(head_buf));
sprintf(head_buf,HTTPD_HDR_STR,strlen(buf)+strlen((char *)&WebConfig_html_start));
httpd_send(req, head_buf, strlen(head_buf));
httpd_send(req, "\r\n", 2);
httpd_send(req, (char *)&WebConfig_html_start, strlen((char *)&WebConfig_html_start));
httpd_send(req, buf, strlen(buf));
// httpd_default_send(req->handle, httpd_req_to_sockfd(req), HTTPD_HDR_STR,strlen(buf)+strlen((char *)&WebConfig_html_start), 0);
/* Space for sending additional headers based on set_header */
// httpd_default_send(req->handle, httpd_req_to_sockfd(req), "\r\n", strlen("\r\n"), 0);
//httpd_default_send(req->handle, httpd_req_to_sockfd(req), (char *)&WebConfig_html_start,strlen((char *)&WebConfig_html_start), 0);
// httpd_default_send(req->handle, httpd_req_to_sockfd(req), buf, strlen(buf), 0);
free(buf);
return ESP_OK;
}
//配置WIFI等待页面
esp_err_t wifi_config_post_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "Free Stack for server task: '%u'", uxTaskGetStackHighWaterMark(NULL));
// httpd_resp_send(req, (char *)&WebConfig_html_start, strlen((char *)&WebConfig_html_start));
ESP_LOGI(TAG, "/echo handler read content length %d", req->content_len);
char* buf = malloc(req->content_len + 1);
size_t off = 0;
int ret;
if (!buf) {
httpd_resp_send_500(req);
return ESP_FAIL;
}
while (off < req->content_len) {
/* Read data received in the request */
ret = httpd_req_recv(req, buf + off, req->content_len - off);
if (ret <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
httpd_resp_send_408(req);
}
free (buf);
return ESP_FAIL;
}
off += ret;
ESP_LOGI(TAG, "/echo handler recv length %d", ret);
}
buf[off] = '\0';
if (req->content_len < 128) {
ESP_LOGI(TAG, "/echo handler read %s", buf);
}
///>下面会将收到的post数据重新回复回去,这里我直接拿来联网,并且将成功配网返回去
#if 0
/* Search for Custom header field */
char* req_hdr = 0;
size_t hdr_len = httpd_req_get_hdr_value_len(req, "Custom");
if (hdr_len) {
/* Read Custom header value */
req_hdr = malloc(hdr_len + 1);
if (req_hdr) {
httpd_req_get_hdr_value_str(req, "Custom", req_hdr, hdr_len + 1);
/* Set as additional header for response packet */
httpd_resp_set_hdr(req, "Custom", req_hdr);
}
}
httpd_resp_send(req, buf, req->content_len);
free (req_hdr);
#else
httpd_resp_send(req, (char *)&WiFiConfig_html_start, strlen((char *)&WiFiConfig_html_start));
#endif
free (buf);
return ESP_OK;
}
{ .uri = "/",
.method = HTTP_GET,
.handler = index_get_handler,
.user_ctx = NULL,
},
{ .uri = "/WebConfig.html",
.method = HTTP_GET,
.handler = web_config_get_handler,
.user_ctx = NULL,
},
{ .uri = "/WiFiConfig.html",
.method = HTTP_POST,
.handler = wifi_config_post_handler,
.user_ctx = NULL,
},
七、WIFI扫描
WIFI扫描,做了一个HTML的表格数据返回,最多15个,表格的结构如下:
<table border="1">
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
</tr>
</table>
程序如下:
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_event.h"
#include "nvs_flash.h"
#define DEFAULT_SCAN_LIST_SIZE 15
static const char *TAG = "scan";
static void print_auth_mode(int authmode,char * buf)
{
switch (authmode) {
case WIFI_AUTH_OPEN:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN");
sprintf(buf+strlen(buf),"<td>%s</td>","AUTH_OPEN");
break;
case WIFI_AUTH_WEP:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP");
sprintf(buf+strlen(buf),"<td>%s</td>","AUTH_WEP");
break;
case WIFI_AUTH_WPA_PSK:
sprintf(buf+strlen(buf),"<td>%s</td>","AUTH_WPA_PSK");
break;
case WIFI_AUTH_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_PSK");
sprintf(buf+strlen(buf),"<td>%s</td>","WPA2_PSK");
break;
case WIFI_AUTH_WPA_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_WPA2_PSK");
sprintf(buf+strlen(buf),"<td>%s</td>","WPA_WPA2_PSK");
break;
case WIFI_AUTH_WPA2_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_ENTERPRISE");
sprintf(buf+strlen(buf),"<td>%s</td>","WPA2_ENTERPRISE");
break;
default:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN");
sprintf(buf+strlen(buf),"<td>%s</td>","UNKNOWN");
break;
}
}
static void print_cipher_type(int pairwise_cipher, int group_cipher)
{
switch (pairwise_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
default:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
switch (group_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
default:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
}
/*
<table border="1">
<tr> 一行
<th>Month</th> th 标题元素 会加粗
<th>Savings</th>
</tr>
<tr>
<td>January</td> 第二行第一列
<td>$100</td> 第二行第二列
</tr>
</table>
[0;32mI (4292) scan: SSID ZZKJ[0m
[0;32mI (4297) scan: RSSI -77[0m
[0;32mI (4302) scan: Authmode WIFI_AUTH_WPA_WPA2_PSK[0m
[0;32mI (4310) scan: Pairwise Cipher WIFI_CIPHER_TYPE_UNKNOWN[0m
[0;32mI (4319) scan: Group Cipher WIFI_CIPHER_TYPE_UNKNOWN[0m
[0;32mI (4328) scan: Channel 6
*/
/* Initialize Wi-Fi as sta and set scan method */
void wifi_scan(char *buf)//将扫描数据存进buf
{
#if 0
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
uint16_t number = DEFAULT_SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;
memset(ap_info, 0, sizeof(ap_info));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
#else
uint16_t number = DEFAULT_SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;
memset(ap_info, 0, sizeof(ap_info));
#endif
esp_wifi_scan_start(NULL, true);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
ESP_LOGI(TAG, "Total APs scanned = %u", ap_count);
sprintf(buf+strlen(buf),"<div align=\"center\">");//写入居中
sprintf(buf+strlen(buf),"Total APs scanned = %u<br/><br/>",ap_count);//写入总共的AP数
sprintf(buf+strlen(buf),"<table border=\"1\">");//写入表格
sprintf(buf+strlen(buf),"<tr><th>SSID</th><th>RSSI</th><th>Authmode</th><th>Channel</th></tr>");//写入标签头
for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++) {
ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);
ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi);
sprintf(buf+strlen(buf),"<tr>");//一行开头
sprintf(buf+strlen(buf),"<td>%s</td>",ap_info[i].ssid);//写入SSID元素
sprintf(buf+strlen(buf),"<td>%d</td>",ap_info[i].rssi);//写入rssi元素
print_auth_mode(ap_info[i].authmode,buf); //写入authomode元素
if (ap_info[i].authmode != WIFI_AUTH_WEP) {
print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher);
}
ESP_LOGI(TAG, "Channel \t\t%d\n", ap_info[i].primary);
sprintf(buf+strlen(buf),"<td>%d</td>",ap_info[i].primary);//写入channal 元素
sprintf(buf+strlen(buf),"</tr>");//完成一行
}
//写入表尾
sprintf(buf+strlen(buf),"</table>");
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)