在上一篇博客中,我们已经完成了AP模式的设置和TCP的连接,现在我们接上篇继续往下讲下TCP连接后我们要做什么?
根据上篇所说,我这次开发ESP8266是为做智能家居,所以我们为了方便,我们不可能把ES8266所要连接写死在程序里,那我们要如何获取到WIFI的SSID和密码呢?
我们可以通过手机APP连接ESP8266发射出来的热点,手机作为客户端连接ESP8266服务端,通过TCP把SSID和密码发送给ESP8266,模块收到后切换成Station模式连接无线网络,同时手机APP连接相同的无线网络,建立UDP连接服务端,等待模块发送数据。这里为方便解析,统一数据格式,模块和APP都是采用的JSON数据格式。对了,至于手机APP这个后面我尽量也出个教程简单说下,后面我看下有空先把APK 先放上来。
好了,我们现在来看下模块收到JSON数据后要怎么处理:这部分程序我们都是在TCP接收回调函数里处理的
cJSON *ssid_json,*psw_json,*type_json,*mac_json;
cJSON *root = cJSON_Parse(pdata);
if(!root){ //不符合JSON格式
os_printf("Error before: [%s]\n",cJSON_GetErrorPtr());
cJSON *Result = cJSON_CreateObject();
cJSON_AddNumberToObject(Result,"status",3);
cJSON_AddStringToObject(Result,"msg","json error");
char *succeedData = cJSON_Print(Result);
char data[1024];
os_sprintf(data,"%s",succeedData);
espconn_send((struct espconn *)arg,data,strlen(data));
}else{
char *ssid,*psw;
int state;
os_printf("接收成功");
//解析字段
cJSON *state_json = cJSON_GetObjectItem(root,"state");
state = state_json->valueint;
if(state == 1)
{
ssid_json = cJSON_GetObjectItem(root,"ssid");
psw_json = cJSON_GetObjectItem(root,"psw");
}
else
{
type_json = cJSON_GetObjectItem(root,"type");
mac_json = cJSON_GetObjectItem(root,"mac");
}
//对state进行jiexi
switch(state){
//当前连接状况查询
case 2: //接收到旗下设备
os_printf("sss%d",state);
os_timer_disarm(&Tcp_Connect_t);
Save_type[Save_Num] = type_json->valueint;
Save_Mac[Save_Num] = mac_json->valuestring;
Save_Num++;
cJSON *Result = cJSON_CreateObject();
cJSON_AddNumberToObject(Result,"state",3);
cJSON_AddStringToObject(Result,"mac",StationMac_String);
char *succeedData = cJSON_Print(Result);
char data[1024];
os_sprintf(data,"%s",succeedData);
espconn_send((struct espconn*)arg,data,strlen(data));
//wifiStationConnect(ssid,psw);
TCP_Connect_Time_Init(4000);
break;
//开始连接AP
case 1:
if(ssid_json && psw_json){
ssid = ssid_json->valuestring;
psw = psw_json->valuestring;
Wifi_SSID = ssid;
Wifi_PSW = psw;
os_printf("SSID:%s",Wifi_SSID);
os_printf("PSW:%s",Wifi_PSW);
//构建JSON包,发送
cJSON *Result = cJSON_CreateObject();
cJSON_AddNumberToObject(Result,"status",2);
cJSON_AddStringToObject(Result,"msg","AP Connect");
char *succeedData = cJSON_Print(Result);
char data[1024];
os_sprintf(data,"%s",succeedData);
espconn_send((struct espconn*)arg,data,strlen(data));
//wifiStationConnect(ssid,psw);
}else{
os_printf("width null\n");
}
}
}
实际上,switch判断里我们只用到状态1的情况,状态2只是我预留的而已。
接下来我们只需要在发送成功的回调函数里进行WiFi连接和等待连接上WIFI后进行UDP连接。
发送成功回调函数
espconn_disconnect(&User_Tcp_Espconn); //断开TCP连接
os_printf("SSID:%s,PSW:%s",Wifi_SSID,Wifi_PSW);
wifiStationConnect(Wifi_SSID,Wifi_PSW); //连接WIFI
udp_client_init(); //UDP连接初始化
void ICACHE_FLASH_ATTR
wifiStationConnect(char *wifi_ssid,char *wifi_psw)
{
struct station_config station_cfg;
wifi_set_opmode(0x01);
os_strcpy(station_cfg.ssid,wifi_ssid);
os_strcpy(station_cfg.password,wifi_psw);
wifi_station_set_config(&station_cfg);
os_delay_us(100);
wifi_station_connect();
}
void Check_WifiState(void) {
static uint8 num = 0;
uint8 getState = wifi_station_get_connect_status();
//如果状态正确,证明已经连接
if (getState == STATION_GOT_IP) {
wifi_set_broadcast_if(0x01); //设置 ESP8266 发送 UDP广播包时,从 station 接口发送
user_udp_espconn.proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp));//分配空间
user_udp_espconn.type = ESPCONN_UDP; //设置类型为UDP协议
user_udp_espconn.proto.udp->local_port = 2000; //本地端口
user_udp_espconn.proto.udp->remote_port = 8266; //目标端口
const char udp_remote_ip[4] = { 255, 255, 255, 255 }; //目标IP地址(广播)
os_memcpy(user_udp_espconn.proto.udp->remote_ip, udp_remote_ip, 4);
espconn_regist_recvcb(&user_udp_espconn, User_Udp_Recv_Cb); //接收
espconn_regist_sentcb(&user_udp_espconn, User_Udp_Sent_Cb); //发送
espconn_create(&user_udp_espconn); //建立 UDP 传输
cJSON *Result = cJSON_CreateObject();
cJSON_AddNumberToObject(Result,"status",2);
cJSON_AddStringToObject(Result,"Tdevice",TargetDevice);
cJSON_AddNumberToObject(Result,"type",type);
cJSON_AddStringToObject(Result,"mac",StationMac_String);
char *succeedData = cJSON_Print(Result);
char data[1024];
os_sprintf(data,"%s",succeedData);
espconn_sent(&user_udp_espconn, data, strlen(data));
}
num++;
if(num > 15)
{
num = 0;
os_timer_disarm(&checkTimer_Wifistate);
MQTT_Connect_Init();
}
}
}
void udp_client_init() //初始化
{
os_timer_setfn(&checkTimer_Wifistate, (os_timer_func_t *) Check_WifiState,
NULL); //设置定时器回调函数
os_timer_arm(&checkTimer_Wifistate, 500, 1); //启动定时器,单位:毫秒
}
TCP连接断开后,我们要等确认模块已经连接上无线网络后再进行UDP连接,进行UDP连接前要确保UDP服务端已经开启了。
TCP接收处理和UDP连接着部分的程序我基本放上来了,大家伙可以直接复制过去,有哪里出错了可以联系我更改。
好了,前期的准备我们基本做完了,下一次我们就要通过MQTT连接阿里云物联平台了,尽请期待!