Esp8266 -- 心知天气GET请求获取json天气数据(代码篇)

官方链接:心知天气api文档

在看代码之前可以先看下这篇文章:心知天气get及url讲解说明

下面代码的一部分是从乐鑫提供的iot_demo中提取并由自己修改来的:

#include "osapi.h"
#include "ets_sys.h"
#include "user_interface.h"
#include "espconn.h"
#include "mem.h"
#include "c_types.h"
//详细格式描述可以参考我写的一篇文章:【https://blog.csdn.net/u013581207/article/details/86697157】
#define get "GET %s HTTP/1.1\r\nHost:%s\r\nAccept-Language:zh-cn\r\nConnection:keep-alive\r\n\r\n"
/***************************函数声明********************************/
LOCAL void user_esp_platform_check_ip(void);
/****************************END***********************************/

/******************************tcp结构体及定时器声明****************************/
LOCAL struct espconn user_conn;
LOCAL struct _esp_tcp user_tcp;
LOCAL os_timer_t client_timer;
ip_addr_t esp_server_ip;
/****************************END***********************************/

/**************************重连的回调函数***********************************/
LOCAL void  ICACHE_FLASH_ATTR
user_esp_platform_reconnect(struct espconn *pespconn)//重连定时器的回调函数
{
	os_printf("user_esp_platform_reconnect\r\n");

    user_esp_platform_check_ip();
}
/******************************************************************************
 * FunctionName : array_cmp
 * Description  : 两个数组之间的比较。
 * Parameters   : a-- 数组1
 * 				  b--数组2
 * 				  length--数组长度
 * Returns      : 两个数组相同返回1,否则返回0
*******************************************************************************/
LOCAL uint8 array_cmp(uint8 *a, uint8 *b, uint8 length)
{
	uint8 i;
    for(i = 0; i < length; i ++)
        if(a[i]!=b[i]) return 0;//出现不相等元素,返回0.
    return 1;//完全相等,返回1。
}
/******************************************************************************
 * FunctionName : user_esp_platform_recon_cb
 * Description  : 连接有一个错误,并且已经被解除分配。
 * Parameters   : arg -- 传递给回调函数的附加参数
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_recon_cb(void *arg, sint8 err)//失败重连的回调函数
{
    struct espconn *pespconn = (struct espconn *)arg;
    uint8 server_ip[4]={116,62,81,138};//远程ip地址
    if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
		os_printf("user_esp_platform_recon_cb\r\n");
		os_timer_disarm(&client_timer);
		os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_reconnect, pespconn);//开启重连定时器
		os_timer_arm(&client_timer, 1000, 0);
	}
	else return;
}
/****************************************************************************/

/******************************************************************************
 * FunctionName : user_esp_platform_sent_cb
 * Description  : 数据已成功发送并被远程主机确认。
 * Parameters   : arg-传递给回调函数的附加参数
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_sent_cb(void *arg)成功发送网络数据的回调函数
{
    struct espconn *pespconn = arg;
    uint8 server_ip[4]={116,62,81,138};//远程ip地址
    if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
    os_printf("user_esp_platform_sent_cb\r\n");
	}
	else return;
}
/******************************************************************************
 * FunctionName : user_esp_platform_sent
 * Description  : 处理应用程序数据并将其发送到主机
 * Parameters   : pespconn -- 用于与主机连接的espconn。
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_sent(struct espconn *pespconn)
{
	uint8 server_ip[4]={116,62,81,138};//远程ip地址
	if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
		char buffer[1024];
		memset(buffer,0,1024);
		os_sprintf(buffer,get,"/v3/weather/now.json?language=en&key=smtq3n0ixdggurox&location=lingao&unit=c","api.seniverse.com");
		os_printf("user_esp_platform_connect_cb\r\n");
		espconn_send(pespconn,buffer,os_strlen(buffer));//发送get请求数据包
	}
	else return;
}
/******************************************************************************
 * FunctionName : user_esp_platform_recv_cb
 * Description  : 处理从服务器接收的数据
 * Parameters   : arg -- 传递给回调函数的附加参数
 *                pusrdata -- 接收到的数据(或连接已关闭时为NULL)!
 *                length -- 接收数据的长度
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_recv_cb(void *arg,char *pdata,unsigned short	len){//成功接收网络数据的回调函数
	struct espconn *pespconn = arg;
	uint8 server_ip[4]={116,62,81,138};//远程ip地址
	if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
		if(pdata==NULL)
			os_printf("Connection has been closed!\r\n");
		else
			os_printf("Data received:\r\n%s\r\n",pdata);//打印输出从服务器接收的数据
	}
	else return;
}

/******************************************************************************
 * FunctionName : user_esp_platform_discon_cb
 * Description  : 成功断开与主机的连接
 * Parameters   : arg -- 传递给回调函数的附加参数
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_discon_cb(void *arg)// TCP 连接正常断开成功的回调函数
{
	//该指针为 SDK 内部维护的指针,不同回调传入的指针地址可能不⼀样,请勿依此判断网络连接。可根据 espconn 结构体中的
	//remote_ip、 remote_port 判断多连接中的不同网络传输
    struct espconn *pespconn = arg;
    uint8 server_ip[4]={116,62,81,138};//远程ip地址
    if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
    	os_printf("user_esp_platform_discon_cb\r\n");
    }
    else return;
}

/******************************************************************************
 * FunctionName : user_esp_platform_connect_cb
 * Description  :  一个新的传入连接已被连接。
 * Parameters   : arg -- 传递给回调函数的附加参数
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_connect_cb(void *arg)//连接服务器成功的回调函数
{
	//该指针为 SDK 内部维护的指针,不同回调传入的指针地址可能不⼀样,请勿依此判断网络连接。可根据 espconn 结构体中的
	//remote_ip、 remote_port 判断多连接中的不同网络传输
    struct espconn *pespconn = arg;
    uint8 server_ip[4]={116,62,81,138};//远程ip地址
    if(array_cmp(pespconn->proto.tcp->remote_ip, server_ip, 4)&&pespconn->proto.tcp->remote_port==80){
		espconn_regist_recvcb(pespconn, user_esp_platform_recv_cb);
		espconn_regist_sentcb(pespconn, user_esp_platform_sent_cb);
		espconn_regist_disconcb(pespconn, user_esp_platform_discon_cb);注册断开连接成功的回调函数
		user_esp_platform_sent(pespconn);
    }
    else return;

}
/******************************************************************************
 * FunctionName : user_esp_platform_connect
 * Description  : 作为与主机的连接而提供的函数。
 * Parameters   : espconn -- 用于连接的espconn
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_connect(struct espconn *pespconn)//tcp连接服务器的函数
{
	os_printf("user_esp_platform_connect\r\n");
    espconn_connect(pespconn);
}

/******************************************************************************
 * FunctionName : user_esp_platform_dns_found
 * Description  : dns找到回调
 * Parameters   : name -- 指向查找的名称的指针
 *                ipaddr -- 指向包含主机名的IP地址的IP_addr_t的指针,如果找不到名称(或任何其他错误),则为NULL。
 *                callback_arg -- 用户指定的回调参数传递给dns_gethostbyname
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)//dns回调函数
{
    struct espconn *pespconn = (struct espconn *)arg;
    char str_buffer[40];
    os_memset(str_buffer,'\0',40);
//解析成功才关闭client_timer定时器
    if (ipaddr == NULL) {//如果解析失败,退出
    	 os_printf("user_esp_platform_dns_found NULL\r\n");
        return;
    }

    if (esp_server_ip.addr == 0 && ipaddr->addr != 0) {//解析成功
        os_timer_disarm(&client_timer);//关闭dns_check定时器
        //格式化字符串
       	 		os_sprintf(str_buffer,"[%s]parse_URL->%d.%d.%d.%d",name,*((uint8 *)&ipaddr->addr),
       	 																*((uint8 *)&ipaddr->addr+1),
       																	*((uint8 *)&ipaddr->addr+2),
       																	*((uint8 *)&ipaddr->addr+3));
       	 		os_printf("%s\n",str_buffer);//打印输出解析域名获得的ip地址
        //初始化剩下的espconn参数
        esp_server_ip.addr = ipaddr->addr;
        os_memcpy(pespconn->proto.tcp->remote_ip, &ipaddr->addr,4);//拷贝远程ip地址

        pespconn->proto.tcp->local_port = espconn_port();//获取可用端口

        pespconn->proto.tcp->remote_port = 80;//http默认的端口
        //注册连接成功的回调函数
        espconn_regist_connectcb(pespconn, user_esp_platform_connect_cb);
        //注册 TCP连接发生异常断开时的回调函数,可以在回调函数中进行重连。
        espconn_regist_reconcb(pespconn, user_esp_platform_recon_cb);
        //tcp连接
        user_esp_platform_connect(pespconn);
    }
}
/******************************************************************************
 * FunctionName : user_esp_platform_dns_check_cb
 * Description  : 1s检查dns找到的回调时间
 * Parameters   : arg -- 传递给回调函数的附加参数
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_dns_check_cb(void *arg)
{
    struct espconn *pespconn = arg;

    os_printf("user_esp_platform_dns_check_cb\n");

    espconn_gethostbyname(pespconn,"api.seniverse.com", &esp_server_ip, user_esp_platform_dns_found);

    os_timer_arm(&client_timer, 1000, 0);
}
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_start_dns(struct espconn *pespconn)
{
    esp_server_ip.addr = 0;//全局变量
    espconn_gethostbyname(pespconn,"api.seniverse.com", &esp_server_ip, user_esp_platform_dns_found);

    os_timer_disarm(&client_timer);//开启client_timer定时器
    os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_dns_check_cb, pespconn);
    os_timer_arm(&client_timer, 1000, 0);
}

/******************************************************************************
 * FunctionName : user_esp_platform_check_ip
 * Description  : 当获得ip地址后,初始化espconn结构体参数
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_check_ip(void)
{
    struct ip_info ipconfig;

    os_timer_disarm(&client_timer);//关闭定时器

    wifi_get_ip_info(STATION_IF, &ipconfig);//查询station接口所获取的ip地址
//已连接上路由器且station接口获取到了ip地址
    if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0) {
    	//初始化部分espconn参数
    			user_conn.proto.tcp = &user_tcp;
    	        user_conn.type = ESPCONN_TCP;
    	        user_conn.state = ESPCONN_NONE;
    	        os_memcpy(user_conn.proto.tcp->local_ip, &ipconfig.ip.addr,4);//拷贝本地ip地址
    	        user_esp_platform_start_dns(&user_conn);//dns开始解析
    }
    else {//重开定时器
               os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_check_ip, NULL);
               os_timer_arm(&client_timer, 100, 0);
            }
}
LOCAL void ICACHE_FLASH_ATTR
user_set_station_config(void)//station接口配置
{
	 char ssid[32]="wifi名称";//接入网络的wifi名
	 char password[64]="wifi密码";//接入网络的密码
	 struct	station_config stationConf;
	 stationConf.bssid_set=0;//无需检查AP的mac地址
	 os_memcpy(&stationConf.ssid,ssid,32);
	 os_memcpy(&stationConf.password,password,64);
	 wifi_station_set_config(&stationConf);
}

LOCAL void ICACHE_FLASH_ATTR
user_esp_platform_init(void){
	        os_timer_disarm(&client_timer);
	        os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_check_ip, NULL);
	        os_timer_arm(&client_timer, 100, 0);
}

/******************************************************************************
 * 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);
	wifi_set_opmode	(STATION_MODE);//station模式
	user_set_station_config();//如果 wifi_station_set_config在 user_init中调用,则 ESP8266 Station接口会在系统初
	//始化完成后,自动连接 AP(路由),无需再调用 wifi_station_connect
	user_esp_platform_init();

}


void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}
/******************************************************************************
 * FunctionName : user_rf_cal_sector_set
 * Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
 *                We add this function to force users to set rf cal sector, since
 *                we don't know which sector is free in user's application.
 *                sector map for last several sectors : ABCCC
 *                A : rf cal
 *                B : rf init data
 *                C : sdk parameters
 * Parameters   : none
 * Returns      : rf cal sector
*******************************************************************************/
user_rf_cal_sector_set(void)
{
    enum flash_size_map size_map = system_get_flash_size_map();
    uint32 rf_cal_sec = 0;

    switch (size_map) {
        case FLASH_SIZE_4M_MAP_256_256:
            rf_cal_sec = 128 - 5;
            break;

        case FLASH_SIZE_8M_MAP_512_512:
            rf_cal_sec = 256 - 5;
            break;

        case FLASH_SIZE_16M_MAP_512_512:
            rf_cal_sec = 512 - 5;
            break;
        case FLASH_SIZE_16M_MAP_1024_1024:
            rf_cal_sec = 512 - 5;
            break;

        case FLASH_SIZE_32M_MAP_512_512:
            rf_cal_sec = 1024 - 5;
            break;
        case FLASH_SIZE_32M_MAP_1024_1024:
            rf_cal_sec = 1024 - 5;
            break;

        case FLASH_SIZE_64M_MAP_1024_1024:
            rf_cal_sec = 2048 - 5;
            break;
        case FLASH_SIZE_128M_MAP_1024_1024:
            rf_cal_sec = 4096 - 5;
            break;
        default:
            rf_cal_sec = 0;
            break;
    }

    return rf_cal_sec;
}

这里已经实现了json数据的获取,下一篇讲解如何使用官方json接口解析json数据。

入口:Esp8266 --深入分析官方json解析源码及如何使用json接口解析心知天气

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值