ESP8266 HTTP实现天气信息实时获取以及JSON解析天气数据

本博文实现了HTTP 每隔20秒请求一次心知天气的天气数据,并且在OLED上显示天气信息,HTTP天气信息使用cJSON进行解析。

本博文Demo所有代码下载地址:https://download.csdn.net/download/zq666888/13125206

效果图如下:

我这里使用的天气API接口是心知天气的,如果学习用的话可以申请免费版的做测试用,详情见:https://www.seniverse.com/login?callback=%2Fproducts%3Fiid%3Dnew

要想实现获取天气信息我们需要经过以下步骤:

1、设置ESP8266工作模式,连接wifi。

/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
    uart_init(115200,115200);	// 初始化串口波特率
    os_delay_us(10000);			// 等待串口稳定
    os_printf("SDK version:%s\n", system_get_sdk_version());
	OLED_Init();// OLED初始化
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5);
	GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1); //绿灯默认灭
	GPIO_OUTPUT_SET(GPIO_ID_PIN(5),0); //红灯默认灭
	OLED_ShowString(0,0,"ESP8266 HTTP");		// ESP8266

	wifi_set_opmode(0x01);//设置wifi为Station模式
	os_memcpy(MyStation.ssid,"Leagend_K2P",strlen("Leagend_K2P"));//要连接的wifi名字
	os_memcpy(MyStation.password,"www.leagend.com",strlen("www.leagend.com"));//要连接的wifi密码
	wifi_station_set_config(&MyStation);//初始化Station参数
	wifi_station_connect();//连接wifi

	os_timer_disarm(&CheckWifiState);//取消定时器
	os_timer_setfn(&CheckWifiState,(os_timer_func_t	*)CheckWifiFunction,NULL);
	os_timer_arm(&CheckWifiState,500,1);
}

2、解析URL,进行DNS解析。

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;
}
http_parse_request_url(ServiceURL,Host,Filename,&Port);//解析URL
os_printf("Host:%s\r\nFilename:%s\r\nPort:%d\r\n",Host,Filename,Port);
os_sprintf(buffer,GET,Filename,Host);
espconn_gethostbyname(&MyEspconn,Host,&addr,DNSFoundCb);//DNS功能

3、根据DNS解析到的IP和端口,在DNS解析回调函数中进行Station相关初始化并进行TCP连接

void ICACHE_FLASH_ATTR
MyStationInit(struct ip_addr *RemoteIP,struct ip_addr *LocalIP,int RemotePort)
{
	MyEspconn.type = ESPCONN_TCP;//连接类型
	MyEspconn.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));//开辟TCP空间
	os_memcpy(MyEspconn.proto.tcp->remote_ip,RemoteIP,4);
	os_memcpy(MyEspconn.proto.tcp->local_ip,LocalIP,4);
	MyEspconn.proto.tcp->remote_port = RemotePort;
	MyEspconn.proto.tcp->local_port = espconn_port();//获取 ESP8266可用的端口
	//和连接失败的回调函数
	espconn_regist_connectcb(&MyEspconn,TcpConnectCb);//注册连接成功的回调函数
	espconn_regist_reconcb(&MyEspconn,TcpReconCb);//注册 TCP 连接发生异常断开时的回调函数
	espconn_connect(&MyEspconn);
}
void DNSFoundCb(const char *name, ip_addr_t *ipaddr, void *callback_arg)
{
	struct	ip_info MyIPInfo;
	os_printf("DNS Found\r\n");
	wifi_get_ip_info(STATION_IF,&MyIPInfo);//查询 Wi-Fi Station 接口或者 SoftAP 接口的IP地址
	MyStationInit(ipaddr,&MyIPInfo.ip,Port);
}

4、在TCP连接成功回调函数中发送GET请求天气数据

void TcpConnectCb(void *arg)
{
	os_printf("Tcp Connect OK!\r\n");
	espconn_regist_recvcb(&MyEspconn,TCPRecvCb);
	espconn_regist_sentcb(&MyEspconn,TCPSendCb);
	espconn_regist_disconcb(&MyEspconn,TCPDisconCb);
	os_printf("buffer:%s\r\n",buffer);
	espconn_send(&MyEspconn,buffer,strlen(buffer));
}

5、从TCP服务器返回的数据中进行JSON解析,获取城市、温度、湿度等天气信息

void TCPRecvCb(void *arg, char *pdata, unsigned short len)
{
	os_printf("Receive Data:%s\r\n",pdata);
	cJSON *Result = 0;
	cJSON *now = 0;
	cJSON *Temper = 0;
	cJSON *Humidi = 0;
	cJSON *Name = 0;
	cJSON *Location = 0;
	cJSON *Array = 0;
	char *Body = strstr(pdata,"{\"");
	if(Body)
	{
		OLED_Clear();
		os_printf("Find JSON Body!\r\n");
		cJSON *DataRoot = cJSON_Parse((const char *)Body);
		if(DataRoot)
		{
			os_printf("JSON Parse OK!\r\n");
			Result = cJSON_GetObjectItem(DataRoot,"results");
			if(Result)
			{
				os_printf("Parse results OK!\r\n");
				Array = cJSON_GetArrayItem(Result,0);//找到数组的第0个元素
				if(Array)
				{
					Location = cJSON_GetObjectItem(Array,"location");
					if(Location)
					{
						Name = cJSON_GetObjectItem(Location,"name");
						if(Name)
						{
							char *str = Name->valuestring;
							os_printf("name:%s\r\n",str);
							OLED_ShowString(0,0,str);
						}
					}
					now = cJSON_GetObjectItem(Array,"now");
					if(now)
					{
						Temper =  cJSON_GetObjectItem(now,"temperature");
						if(Temper)
						{
							char *Tem = Temper->valuestring;
							os_printf("temperature:%s\r\n",Tem);
							OLED_ShowString(0,2,"Tem:");
							OLED_ShowString(33,2,Tem);
						}
						Humidi =  cJSON_GetObjectItem(now,"humidity");
						if(Humidi)
						{
							char *Hum = Humidi->valuestring;
							os_printf("humidity:%s\r\n",Hum);
							OLED_ShowString(0,4,"Hum:");
							OLED_ShowString(33,4,Hum);
						}
					}
				}
			}
			else
			{
				os_printf("Parse results error!\r\n");
			}
			cJSON_Delete(DataRoot);
		}
		else
		{
			os_printf("JSON Parse Error!\r\n");
		}
	}
	else
	{
		os_printf("Not Find JSON Body!\r\n");
	}
	os_timer_disarm(&BreakTcp);
	os_timer_setfn(&BreakTcp,(os_timer_func_t	*)BreakTcpFun,NULL);
	os_timer_arm(&BreakTcp,5000,0);
}

6、设置一个定时器,处理完数据断开TCP连接,20秒后重新请求数据并解析。

void TCPDisconCb(void *arg)
{
	os_printf("Tcp Break!\r\n");
	os_timer_disarm(&ConnectTcp);
	os_timer_setfn(&ConnectTcp,(os_timer_func_t	*)ConnectTcpFun,NULL);
	os_timer_arm(&ConnectTcp,20000,0);
}

关于cJSON的具体用法请参考:https://zhuanlan.zhihu.com/p/53730181

 

 

 

 

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Karl Zhangq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值