Featured image of post 树莓派之esp-01webconfig配网

树莓派之esp-01webconfig配网

前言

玩esp-01有断时间了,自己使用homeassistant搭建后台控制中心,esp-01做终端控制灯、控制风扇、温度检测等等。但在控制之前esp-01需要配网,说到配网baidu搜索到最多应该就是smartconfig,以及微信的airkiss。但是不管是smartconfi或airkiss配置网,配置过程很不稳定,经常无法配置成功然后就只能断电重来;另一个原因是smartconfig需要app上配置很是麻烦。以上原因让我去寻找找到了另一种配网方式webconfig

webconfig基本思路

基本思路是ESP8266工作AP模式下,作为TCP Server监听TCP Client的连接。因为网页HTTP默认的端口是80,所以ESP8266作为TCP Server的端口需要设置为80。电脑连接上ESP8266的AP后,网页访问默认IP地址192.168.4.1,此时ESP8266就会收到来自网页的HTTP的Get请求,此请求数据为HTML格式。ESP8266收到请求后,读出保存在Flash中的HTML格式网页,并将带有HTML应答头的HTML网页发送给网页,网页端就可以显示出网页。

实现过程

从flash中读取上次保留的wifi信息,若有wifi信息进入station模式反之进程softap模式等待配网

void ICACHE_FLASH_ATTR
init_done_cb_init(void)
{   
    struct station_config stconfig;
    struct softap_config  apconfig;
    
    print_chip_info();
    
    os_memset(&stconfig, 0, sizeof(struct station_config));
    wifi_station_get_config_default(&stconfig);
    if(os_strlen(stconfig.ssid) != 0){
        os_printf("ssid[%s]pass[%s]", stconfig.ssid, stconfig.password);
        wifi_set_opmode(STATION_MODE);
        wifi_station_set_reconnect_policy(TRUE);
        wifi_station_set_auto_connect(TRUE);
    }
    else{
        wifi_set_opmode(SOFTAP_MODE);
        wifi_softap_get_config(&apconfig);
        os_memset(apconfig.ssid, 0, 32);
        os_memset(apconfig.password, 0, 64);
        os_sprintf(apconfig.ssid,"ESP_%X",system_get_chip_id());
        apconfig.authmode = AUTH_OPEN;
        apconfig.ssid_len = 0;
        apconfig.max_connection = 5; 
        wifi_softap_set_config(&apconfig);
        wifi_station_set_reconnect_policy(FALSE);
        wifi_station_set_auto_connect(FALSE);
        wifi_station_disconnect();
    }
#if PLUG_DEVICE
    user_plug_init();
#elif FAN_DEVICE
    user_fan_init();
#elif DS18B20_DEVICE
    ds_init();
#endif
    user_webserver_init(SERVER_PORT);
}

在TCP Server接收函数中实现解析GET请求获取配网页面,POST请求配置

#define HTML	"<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/></head>"	\
				"<body align=\"center\"><h2>WiFi Settings</h2><form method='post'>" \
				"<input type='text' name='ssid' placeholder='ssid'><br>"	\
				"<input type='text' name='pass' placeholder='pass'><br>"  \
				"<input type='submit'><br></form></body></html>"

LOCAL void ICACHE_FLASH_ATTR
webconfig_set_wifi(char* urlparam){
	char *p = NULL, *q = NULL;
	char ssid[10], pass[15];

	os_memset(ssid, 0, sizeof(ssid));
	os_memset(pass, 0, sizeof(pass));

	p = (char *)os_strstr(urlparam, "ssid=");
	q = (char *)os_strstr(urlparam, "pass=");
	if ( p == NULL || q == NULL ){
		return;
	}
	os_memcpy(ssid, p + 5, q - p - 6);
	os_memcpy(pass, q + 5, os_strlen(urlparam) - (q - urlparam) - 5);
	os_printf("ssid[%s]pass[%s]\r\n", ssid, pass);
	
	wifi_set_opmode(STATION_MODE);
	struct station_config stConf;
	stConf.bssid_set = 0;
	os_memset(&stConf.ssid, 0, sizeof(stConf.ssid));
	os_memset(&stConf.password, 0, sizeof(stConf.password));
	
	os_memcpy(&stConf.ssid, ssid, os_strlen(ssid));
	os_memcpy(&stConf.password, pass, os_strlen(pass));

	wifi_station_set_config(&stConf);
	//重启
	system_restart();
	return ;
}

LOCAL void ICACHE_FLASH_ATTR
webserver_recv(void *arg, char *pusrdata, unsigned short length){
	struct espconn *ptrespconn = arg;
	URL_Frame *pURL_Frame = NULL;
	char *pParseBuffer = NULL;
	char szOut[512];
	int stat = -1;
	
	static char post_data[1024];
	static bool last_post = false;

	os_printf("length[%d]\r\n", length);
	os_printf("recv[%s]\r\n", pusrdata);
	
	if(check_data(pusrdata, length) == false){
		os_printf("check error\r\n");
		data_send(ptrespconn, false, NULL);
		return ;
	}
	if(save_data(pusrdata, length) == false){
		os_printf("save_data error\r\n");
		data_send(ptrespconn, false, NULL);
		return ;
	}
	pURL_Frame = (URL_Frame *)os_zalloc(sizeof(URL_Frame));
	parse_url(precvbuffer, pURL_Frame);
	os_printf("Type[%d]\r\n", pURL_Frame->Type);
	os_printf("pSelect[%s]\r\n", pURL_Frame->pSelect);
	os_printf("pCommand[%s]\r\n", pURL_Frame->pCommand);
	os_printf("pFilename[%s]\r\n", pURL_Frame->pFilename);
	switch (pURL_Frame->Type) {
		case GET:
			os_printf("We have a GET request.\n");
			if((strlen(pURL_Frame->pSelect) == 1) && 
				(os_strncmp(pURL_Frame->pSelect, "/", 1) == 0)){
				//获取webconfig页面
				html_send(ptrespconn, true, HTML);
			}
			if(os_strcmp(pURL_Frame->pSelect, "config") == 0 &&
				os_strcmp(pURL_Frame->pCommand, "command") == 0) {
				os_memset(szOut, 0, sizeof(szOut));
#if PLUG_DEVICE
				stat = user_plug_getmethed(szOut);
#elif FAN_DEVICE
				stat = user_fan_getmethed(szOut);
#elif DS18B20_DEVICE
				stat = user_ds18b20_getmethed(szOut);
#endif
				if(stat==0){
					os_printf("get22szOut[%s]\r\n", szOut);
					data_send(ptrespconn, true, szOut);
				}else
					data_send(ptrespconn, false, NULL);
			}else
				data_send(ptrespconn, false, NULL);
			break ;
		case POST:
			os_printf("We have a POST request.\n");
			pParseBuffer = (char *)os_strstr(precvbuffer, "\r\n\r\n");
			if (pParseBuffer == NULL) {
				break;
			}
			pParseBuffer += 4;
			os_printf("pParseBuffer[%s]\r\n", pParseBuffer);
			
			if((strlen(pURL_Frame->pSelect) == 1) && 
				(os_strncmp(pURL_Frame->pSelect, "/", 1) == 0)){
				//webconfig配网
				webconfig_set_wifi(pParseBuffer);
				data_send(ptrespconn, false, NULL);
				break ;
			}else if (os_strcmp(pURL_Frame->pSelect, "config") == 0 &&
				os_strcmp(pURL_Frame->pCommand, "command") == 0) {
				os_memset(szOut, 0, sizeof(szOut));
#if PLUG_DEVICE
				stat = user_plug_postmethed(pParseBuffer, szOut);
#elif FAN_DEVICE
				stat = user_fan_postmethed(pParseBuffer, szOut);
#elif DS18B20_DEVICE
				stat = user_ds18b20_postmethed(pParseBuffer, szOut);
#endif
				if(stat == 0){
					os_printf("post22szOut[%s]\r\n", szOut);
					data_send(ptrespconn, true, szOut);
				}else
					data_send(ptrespconn, false, NULL);
				
			} else {
				os_printf("\r\nparse error!\r\n");
				data_send(ptrespconn, false, NULL);
			}
			break ;
	}
	
	if (precvbuffer != NULL){
		os_free(precvbuffer);
		precvbuffer = NULL;
	}
	os_free(pURL_Frame);
	pURL_Frame = NULL;
}

最后

很简单。本人参考使用Web页面配置ESP8266的参数思路开发修改。

git链接https://gitee.com/review/esp-01.git