【ESP8266】NONOS SDK开发,发送HTTP请求
网络方面不是很懂,可能描述有一点不准确。
主要是通过ESP8266,在NONOS-SDK环境下,用URL地址,发出HTTP请求,接收并处理信息。
假设已经大致了解厂家提供的SDK,以及Eclipse开发环境如何使用,现在大致要做的是以下几步:
1、连上WiFi(连上网络)
2、与URL地址的服务器建立TCP连接
3、发出HTTP请求
4、接收并处理信息
现在就开始一步步地讲:
一、连上WiFi
连上WiFi这里我采用比较笨的方式,就是固定的WiFi和密码,直接连上就是了
需要用到几个函数:
1 2 3 4 5 6 7 8 9 10 11 bool wifi_set_opmode (uint8 opmode); //设置ESP8266模式,选择station模式wifi_station_set_config(&stationConf); //设置连接WiFi的参数//有结构体:struct station_config {uint8 ssid[32]; //ssiduint8 password[64]; //密码uint8 bssid_set;uint8 bssid[6];};bool wifi_station_connect (void); //连接WiFiuint8 wifi_station_get_connect_status (void); //获取连接状态来自CODE的代码片
wifi_func
1)设置ESP8266 的工作模式;
2)设置好WiFi的SSID和密码;
3)开始连接WiFi;
4)检查WiFi连接状态,若为5则连接成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 void init_CollectWifi(){uint8 wifistatus;struct station_config stationConf;os_memcpy(&stationConf.ssid,WIFI_SSID,32); //输入路由器账号os_memcpy(&stationConf.password,WIFI_PWD,64); //输入路由器密码//stationConf.bssid_set = 0;wifi_station_set_config(&stationConf);//设置wifi_station的接口,并保存到flash。#ifdef DEBUGos_printf("\r\n call connect_wifi\n");os_printf("wifi name: %s\n",stationConf.ssid);os_printf("wifi pw:%s\n",stationConf.password);os_printf("wifi connecting..\n");#endifif (wifi_station_connect()){#ifdef DEBUGos_printf("wifi_station_connect = true\n");#endif}else{#ifdef DEBUGos_printf("wifi_station_connect = flase\n");#endif}//os_delay_us(2000000);wifistatus = wifi_station_get_connect_status();#ifdef DEBUGos_printf("wifi connect status = %d\n",wifistatus);os_printf("wifi status = %s\n", Word_Status[wifistatus]);#endif}来自CODE的代码片
init_collectwifi.c
在开始初始化的时候应该还要有一句 wifi_set_opmode(STATION_MODE);
二、建立TCP连接
这里又分为几步:
1)解析URL,获取域名
要建立TCP连接,首先应该获取服务器的域名。
举个例子:https://code.****.net/snippets_manage
那么域名就应该是code.****.net,我们要建立连接也是与这个服务器建立连接,所以我们需要把URL地址拆开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void ICACHE_FLASH_ATTR http_parse_request_url(char *URL,char *host,char *filename,unsigned short *port){char *PA;char *PB;memset(host,0,sizeof(host));memset(filename,0,sizeof(filename));*port=0;if(!(*URL)) return;PA=URL;if(!strncmp(PA,"http://",strlen("http://")))PA=URL+strlen("http://");if(!strncmp(PA,"https://",strlen("https://")))PA=URL+strlen("https://");PB=strchr(PA,'/');if(PB){memcpy(host,PA,strlen(PA)-strlen(PB));if(PB+1){memcpy(filename,PB+1,strlen(PB-1));filename[strlen(PB)-1]=0;}host[strlen(PA)-strlen(PB)]=0;}else{memcpy(host,PA,strlen(PA));host[strlen(PA)]=0;}PA=strchr(host,':');if(PA)*port=atoi(PA+1);else*port=80;}来自CODE的代码片
http_parse_request_url.c
2)解析域名,转换成IP地址
这里,当它找到对应的IP地址后,会有调用回调函数,我们可以在回调函数中进行TCP连接
我是这样调用这个函数的:espconn_gethostbyname(&user_tcp_conn,host, &addr,user_esp_dns_found);
3)TCP连接
获得了IP地址后就可以连接了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 /** 函数名: iot_station_init* 描述: 以ESP8266为客户端,建立tcp连接* 输入: remote_ip:服务器IP* local_ip:本地IP* remote_port:服务器端口* 返回: true:成功* 调用: 无*/bool ICACHE_FLASH_ATTR iot_station_init(struct ip_addr *remote_ip ,struct ip_addr *local_ip ,int remote_port ){#ifdef DEBUGos_printf("\r\ncall iot_station_init\n");#endifuser_tcp_conn.type = ESPCONN_TCP;user_tcp_conn.state = ESPCONN_NONE;user_tcp_conn.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));os_memcpy(user_tcp_conn.proto.tcp->local_ip ,local_ip,4);os_memcpy(user_tcp_conn.proto.tcp->remote_ip ,remote_ip,4);user_tcp_conn.proto.tcp->local_port = espconn_port();user_tcp_conn.proto.tcp->remote_port = remote_port;espconn_regist_connectcb(&user_tcp_conn ,user_tcp_connect_cb);espconn_regist_reconcb(&user_tcp_conn ,user_tcp_recon_cb);#ifdef DEBUGos_printf("espconn_connect\n");#endifespconn_connect(&user_tcp_conn);return true;}来自CODE的代码片
iot_station_init
在(二)中的函数应该是在要发出命令时一气呵成的,所以这里我们应该封装好一个接口函数,
只要用户给出URL和发送的命令时,系统就能自动完成功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void ICACHE_FLASH_ATTR HttpReadFile(char *URL,char *method,char *postdata){struct ip_addr addr;memset(buffer,0,1024);#ifdef DEBUGos_printf("\r\nThe URL request:\n%s\n", URL);#endifhttp_parse_request_url(URL,host,filename,&port);if(strcmp(method,"GET")==0){os_sprintf(buffer,GET,filename,host);}else{os_sprintf(buffer,POST,filename,strlen(postdata),host,postdata);}espconn_gethostbyname(&user_tcp_conn,host, &addr,user_esp_dns_found);}来自CODE的代码片
HttpReadFile
这里有包含头文件 my_client.h ,里面定义了GET和POST的格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #ifndef APP_INCLUDE_MY_CLIENT_H_#define APP_INCLUDE_MY_CLIENT_H_#include "user_main.h"#include "espconn.h"#include "mem.h"char buffer[1024];#define GET "GET /%s HTTP/1.1\r\nAccept: */*\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n"#define POST "POST /%s HTTP/1.1\r\nAccept: */*\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n%s"struct espconn user_tcp_conn;//工作模式初始化,传三个参:远端IP,本地IP,远端端口。bool iot_station_init(struct ip_addr *remote_ip ,struct ip_addr *local_ip ,int remote_port );void user_tcp_connect_cb(void *arg);void user_tcp_reconnect_cb(void *arg ,sint8 err); //连接失败时会执行这个函数,可以在本回调函数中进行重连。void user_tcp_recv_cb(void *arg ,char *pdata ,unsigned short len); //注册成功接收网络数据的回调函数void user_tcp_sent_cb(void *arg); //注册网络数据发送成功的回调函数void user_tcp_discon_cb(void *arg); //注册 TCP 连接正常断开成功的回调函数#endif /* APP_INCLUDE_MY_CLIENT_H_ */来自CODE的代码片
my_client.h
四、接收信息
在之前一直没有讲,在建立了TCP连接后有四个很重要的回调函数要声明。
就是上面my_client.h中的四个回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 /** 函数名: user_tcp_sent_cb* 描述: tcp发送成功后的回调函数* 输入: arg:tcp连接句柄* 返回: 无* 调用: 无*/void ICACHE_FLASH_ATTR user_tcp_sent_cb(void *arg){#ifdef DEBUGos_printf("\r\nsend success!");#endif}/** 函数名: user_tcp_discon_cb* 描述: tcp连接断开后的回调函数* 输入: arg:tcp连接句柄* 返回: 无* 调用: 无*/void ICACHE_FLASH_ATTR user_tcp_discon_cb(void *arg){#ifdef DEBUGos_printf("\r\ndisconnect success!");#endif}/** 函数名: user_tcp_recv_cb* 描述: tcp接收成功后的回调函数* 输入: arg:tcp连接句柄* pdata:收到数据* len:收到数据长度* 返回: 无* 调用: 无*/void ICACHE_FLASH_ATTR user_tcp_recv_cb(void *arg, char *pdata, unsigned short len){}/** 函数名: user_tcp_recon_cb* 描述: tcp重连成功后的回调函数* 输入: arg:tcp连接句柄* err:错误码* 返回: 无* 调用: 无*/void ICACHE_FLASH_ATTR user_tcp_recon_cb(void *arg, sint8 err){#ifdef DEBUGos_printf("connect err,errno:%d\r\n",err);#endifespconn_connect((struct espconn *)arg);}/** 函数名: user_tcp_connect_cb* 描述: tcp连接成功后的回调函数,需要再注册一些回调函数* 输入: arg:tcp连接句柄* 返回: 无* 调用: 无*/void ICACHE_FLASH_ATTR user_tcp_connect_cb(void *arg){struct espconn *pespconn=arg;#ifdef DEBUGos_printf("\r\nconnect success!");#endif}来自CODE的代码片
tcp_cb
收到信号后的处理,我们就写在recv_cb里面就可以了
但是有一点要注意的是:我们使用的这个NONOS_SDK,它是有看门狗的,当回调函数执行时间过长是会导致重启的!
HTTP和URL介绍 http://www.cnblogs.com/LDSmallCat/p/4942039.htmlESP8266 SDK 编程手册.pdf