esp8266燒錄Html文件,實現內置網頁控制設備!


代碼地址如下:
http://www.demodashi.com/demo/14321.html


一、前言;


  • 這個月也快結束了,時間真快,我服務器知識自學依然在路途中,這幾天聽到熱點網頁配置esp8266連接路由器,那么我想這個不是很復雜,不過需要一些通訊協議的基礎,以及對esp8266SDK開發的熟悉,這幾天擼了幾下也就輕松弄出來了!不過我今天給大家帶來的是實現的原理,我是用作於gpio口控制,也就是一盞燈的點亮點滅!當然了,你可以沿着我思路去做網頁內置配網哦!

二、整體思路;


  • ①:以手機瀏覽器為例,其訪問指定的ip地址,過程是怎么樣的?

     我們都在用手機瀏覽器,很少知道他是怎么實現訪問交互數據的。這里我們把esp8266作為服務器端,手機瀏覽器作為客戶端,一般地,都是get請求,除非指定post提交,而請求的數據格式,大家可以去百度下http協議的數據格式,這里不再累贅!而請求之后,esp8266那肯定是要以http協議數據來回復內容的,這內容也就包含了gpio的管腳狀態!從而實現了數據交互!

  • ②:編寫好的html對應燒錄的地址,應該怎么注意什么?

      這里我就不再多說html的文件怎么編寫,這需要一定的前端知識。對應的燒錄地址必須在代碼塊外的地址燒錄,大家不懂哪些是代碼塊外的地址,可以去看看我上個月寫的25q16存儲芯片的分布,點我查看!,之后我們需要在代碼中讀取這個網頁,之后發送給客戶端就可以了!


三、編寫一個簡單的Html文件;


  • 非常簡單,我這里直接上代碼:
    • 用的是post提交,不是get請求!
    • 當點擊開燈,發送powerOn=1,點擊關燈發送powerOn=0
    • 注意編碼是utf-8!

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8"></meta><title>esp8266內置網頁單開關燈</title></head>
	<body>
		<h2 align="center">esp8266熱點內置網頁單開關燈By半顆心臟</h2>
		<h3 align="center">%s</h3>
		<form method="post"action="setLight">
			<table align="center"><tr><td>開燈:</td><td>
				<button name="powerOn"type="submit"value="1">點我開燈</button>
			</td></tr><tr><td>關燈:</td><td>
				<button name="powerOff"type="submit"value="0">點我關燈</button>
			</td></tr>
		   </table>
	</form>
</body>
</html>

用電腦瀏覽器打開預覽如下:


四、esp8266編程;


看標題大家都知道,這個設備esp8266是作為一個熱點讓客戶端去主動連接,那么esp8266必須要開啟熱點模式,我這里讓它固定一個ip地址192.168.5.1,當然了,你也可以不設置固定地址,因為默認就是192.168.4.1!開啟熱點之后,等待客戶端連接,如果客戶端有成功連接后,開啟tcp服務器(其實就是web服務器第一步),這時候就是一直處於和客戶端連接交互數據的狀態了!

4.1 配置熱點模式,開啟軟路由!

下面代碼中的webEsp8266是設備發出的熱點名字,xh12345678是密碼,192, 168, 5, 1是固定自定義的ip地址,允許最大四個的客戶端連接,而且分配的ip是從192, 168, 5, 100192, 168, 5, 105;


	wifi_set_opmode(SOFTAP_MODE);
	struct softap_config *config = (struct softap_config *) zalloc(
			sizeof(struct softap_config)); // 初始化

	wifi_softap_get_config(config);
	sprintf(config->ssid, "webEsp8266");
	sprintf(config->password, "xh12345678");
	config->authmode = AUTH_WPA_WPA2_PSK;
	config->ssid_len = 0;
	config->max_connection = 4;
	wifi_softap_set_config(config); // Set ESP8266 soft-AP config
	free(config);

	struct station_info * station = wifi_softap_get_station_info();
	while (station) {
		printf("bssid : MACSTR, ip : IPSTR/n", MAC2STR(station->bssid),
				IP2STR(&station->ip));
		station = STAILQ_NEXT(station, next);
	}
	wifi_softap_free_station_info(); // Free it by calling functionss
	wifi_softap_dhcps_stop(); // disable soft-AP DHCP server

	//配置dhcp,固定esp8266的ip為 192, 168, 5, 1
	struct ip_info info;
	IP4_ADDR(&info.ip, 192, 168, 5, 1);
	IP4_ADDR(&info.gw, 192, 168, 5, 1);
	IP4_ADDR(&info.netmask, 255, 255, 255, 0);
	wifi_set_ip_info(SOFTAP_IF, &info);
	struct dhcps_lease dhcp_lease;
	IP4_ADDR(&dhcp_lease.start_ip, 192, 168, 5, 100); //分配的網段ip開始
	IP4_ADDR(&dhcp_lease.end_ip, 192, 168, 5, 105); //分配的網段ip結束
	wifi_softap_set_dhcps_lease(&dhcp_lease);
	wifi_softap_dhcps_start(); // 使能 soft-AP DHCP 服務

4.2 創建tcp服務器!

代碼比較復雜,總的來說,先初始化socket,之后bind綁定端口號,大家都知道瀏覽器的默認訪問的端口是80,那么這里也肯定是80,然后監聽這個端口,阻塞等待消息!

	int32 listenfd;
	int32 ret = 0;
	char input[1024] = { 0 };
	char output[1024] = { 0 };
	struct sockaddr_in server_addr, remote_addr;
	int stack_counter = 0;
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = INADDR_ANY;
	server_addr.sin_len = sizeof(server_addr);
	server_addr.sin_port = htons(80);

	printf("[XHLogUtils] Task_local_server init succeed!!! \n");

	/* Create socket for incoming connections */
	do {
		listenfd = socket(AF_INET, SOCK_STREAM, 0);
		printf("[XHLogUtils] Create socket for incoming connections !!! \n");
		if (listenfd == -1) {
			printf(
					"[XHLogUtils] Create socket for incoming connections -1 !!! \n");
			vTaskDelay(1000 / portTICK_RATE_MS);
		}
	} while (listenfd == -1);

	/* Bind to the local port */
	do {
		ret = bind(listenfd, (struct sockaddr * )&server_addr,
				sizeof(server_addr));
		printf("[XHLogUtils] Create socket binding !!! \n");
		if (ret != 0) {
			printf("Create socket binding = -1 \n");
			vTaskDelay(1000 / portTICK_RATE_MS);
		}
	} while (ret != 0);

	do {
		// Listen to the local connection
		ret = listen(listenfd, 4);
		printf("[XHLogUtils] Create socket listening !!! \n");
		if (ret != 0) {
			printf(
					"[XHLogUtils] Create socket listening = -1 will close!!! \n");
			vTaskDelay(1000 / portTICK_RATE_MS);
		}
	} while (ret != 0);

	int32 client_sock;
	int32 len = sizeof(struct sockaddr_in);

	for (;;) {

		printf(
				"[XHLogUtils] Task_local_server block here waiting remote connect request !!! \n");

		/*block here waiting remote connect request*/
		if ((client_sock = accept(listenfd, (struct sockaddr * )&remote_addr,
				(socklen_t * )&len)) < 0) {
			printf("[XHLogUtils] acceptting < 0...\n");
			continue;
		} else {
			printf("[XHLogUtils] acceptting > 0...\n");
		}
	}

4.3 對來自客戶端數據的處理以及回復!

前面已經說了,我們點擊開關燈時候,是post提交數據,所以我們是先判斷否為post提交,然后對里面的數據進一步剖析,我們看看客戶端發來了什么內容?對比下面可以看到,在body里面數據不一樣,開燈時候是powerOn=1,而關燈是powerOn=0!那么我們就從body里面數據剖析就可以啦?這豈不是很簡單?

  • 開燈請求得到客戶端數據:
POST /setLight HTTP/1.1
Host: 192.168.5.1
Connection: keep-alive
Content-Length: 9
Cache-Control: max-age=0
Origin: http://192.168.5.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; MI 8 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,image/sharpp,image/apng,image/tpg,*/*;q=0.8
Referer: http://192.168.5.1/setLight
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,en-US;q=0.8

powerOn=1
  • 關燈請求得到客戶端數據:
POST /setLight HTTP/1.1
Host: 192.168.5.1
Connection: keep-alive
Content-Length: 9
Cache-Control: max-age=0
Origin: http://192.168.5.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; MI 8 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,image/sharpp,image/apng,image/tpg,*/*;q=0.8
Referer: http://192.168.5.1/setLight
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,en-US;q=0.8

powerOn=0
  • body里面數據剖析,進一步得到指定的動作執行gpio!!並回復給客戶端,注意之后主動要斷開tcp連接!

			//確定是post請求
			if (input[0] == 'P' && input[1] == 'O' && input[2] == 'S'
					&& input[3] == 'T') {

				//顯示client 端的網絡地址
				char *pBody = NULL;
				//得到body
				get_http_body(input, &pBody);
				char attribute[] = { "" };
				//截取之后保存的位置,源字符串,要截取的字符串的長度
				strncpy(attribute, pBody, strlen(pBody) - 2);
				//獲取value設置數值
				char *pValue = (char *) strstr(pBody, "=");
				pValue += 1;
				if (strcmp(pValue, "0") == 0) {
					GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 1);
				} else {
					GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 0);
				}

			}

			char *pStatus;
			if (GPIO_INPUT_GET(12) == 0x00) {
				pStatus = "智能燈的當前狀態:開";
			} else {
				pStatus = "智能燈的當前狀態:關";
			}

			char tempHttpHead[1024], tempHttpBody[1024];
			sprintf(tempHttpHead, httpHead, strlen(tempSaveData));
			//協議頭拼接到發送的變量
			sprintf(sendstr, tempHttpHead);
		    //設置結束符
			tempSaveData[594] = 0;
			//協議body拼接到發送的變量
			sprintf(tempHttpBody, tempSaveData, pStatus);
			//拼接到發送全部消息
			strcat(sendstr, tempHttpBody);
			
			write(client_sock, sendstr, strlen(sendstr));


五、esp8266flash讀取網頁的注意要點;


  • 在我之前說到的是先通過工具把html網頁燒錄到flash芯片,我這里使用的是25q32,可用的空間會比較大,我這里就燒錄到0x1F4000,計算之后是哪個扇區呢?大家可以算下,0x1F4000換算十進制就是‭2048000‬,一個扇區是4096 bytes,而‭2048000 / 4096 = 500 ‬ ,也就是第 500 個扇區了!於是我們代碼這樣讀取:
    //500*4096 相當於  0x1F4000 ,也就是 0x1F4 * 4096
	spi_flash_read(500 * 4096, (uint32 *) &tempSaveData, sizeof(tempSaveData));
	printf("get Html Content:  %s \n", tempSaveData);


  • 在拿到了網頁信息之后,要自己設置字符串內容的結束符,這就需要我們的Html文件有多大?注意:我們要的是顯示全部內容下的時候才拿到這個Html文件大小,注意我們上面的是格式符%s,取出來的當然會小很多!
           //設置結束符
			tempSaveData[594] = 0;


六、其他注意要點;


  • 上面注意這個文件大小,再來設置結束符!如果設置不對,設置過多或過少,會影響顯示效果哦!切記切記!
  • 下面是燒錄固件和Html文件的燒錄截圖!

  • 下面是客戶端手機瀏覽器截圖!

esp8266燒錄Html文件,實現內置網頁控制設備!

代碼地址如下:
http://www.demodashi.com/demo/14321.html

注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM