ESP8266获取网络天气

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wangzibigan/article/details/86063406

使用ESP8266模块来获取网络数据(天气,时间等),还是挺简单的。

一步一步来。

1.初始化串口与相关IO

使得MCU可正常使用串口的发送与接收,以及一些IO控制ESP8266的使能端与电源。

2检测模块

通电后等待几秒钟,串口发送"AT\r\n",检测有回应"OK"则代表模块在线使用。

3.连接路由热点

发送"AT+CWJAP?\r\n"可以获取当前连接的路由,如果没有连接正确的路由,则使用"AT+CWLAP\r\n"命令获取当前路由列表。

使用"AT+CWJAP=\"ssid_str\",\"password_str"\r\n"连接相关路由热点,ssid_str为热点名,password_str为密码。注意其中的转义符号\。

4.连接网络天气服务器

这个可以自己百度搜索,我使用的api.yytianqi.com:80,还有api.k780.com:88。冒号前是服务器,冒号后是端口。

以yytianqi举例,可以上他们的网站查看API说明。使用前需要注册一个账号。(k780有公共测试的秘钥不需要注册也能使用)

网站:http://www.yytianqi.com/api.html

发送"AT+CIPSTART=\"TCP\",\"api.yytianqi.com\",80\r\n"使用TCP方式连接服务器,然后就可以与之通信。这时可以使用AT命令进入透传模式,不过我不建议这样,因为推出透传模式有点坑。所以推荐直接使用发送命令:"AT+CIPSEND=num\r\n",num是实际需要发送字符串的字节数。继续,使用GET命令请求数据"GET http://api.yytianqi.com/observe?city=CH280601&key=xxxx\r\n",xxxx是自己的秘钥,注册后网站提供,"city="后面是城市编号。

这时服务器会返回相关的数据,数据是JSON格式。前面我写过冠以JSON在KEIL上的移植使用。这里正好用上了。通常服务器返回数据后会自动关闭TCP连接。不过为了保险最好发送"AT+CIPCLOSE\r\n"关闭与服务器的连接。

5.数据解析

{
    "code": 1,
    "msg": "Sucess",
    "counts": 28,  //访问的剩余次数。
    "data": {
        "cityId": "CH010100",  //城市id
        "cityName": "北京",  //城市名称
        "lastUpdate": "2016-03-09 17:10:00",  //实况更新时间
        "tq": "多云",  //天气现象
        "numtq": "01",  //天气现象编码
        "qw": "5.0",  //当前气温
        "fl": "微风",  //当前风力
        "numfl": 0,  //当前风力编码
        "fx": "无持续风向",  //当前风向
        "numfx": "0",  //当前风向编码
        "sd": "10"  //相对湿度
    }
}

理论上,JSON数据也就是特定格式的字符串,可以自己对字符串进行解析而不需要移植JSON。开始我也试过,比如使用strstr()函数寻找特定字符串,但最终发现不稳健而且麻烦。原因是服务器返回的数据模式不是每次都固定不变,比如某个内容,有时使用字符型,有时直接数字,打个比方也即是12和"12"的区别,甚至有时是浮点型有时又会变成整型数据。而且各个内容顺序不保证一样。所以还是建议移植JSON。

//天气内容结构
typedef struct
{
   char numtq[6];//天气状况号
   char qw[6];//气温
   char numfl[6];//风力号
   char numfx[6];//风向号
   char sd[6];//湿度
   char counts;//剩余次数
   char ok;//完成
} _weatherType;

//获取json内某个item的天气相关内容 并转为字符串形式
static void _getValue(const cJSON *item ,char val[])
{
    switch(item->type)
    {
        case cJSON_False:
            break;
        case cJSON_True:
            break;
        case cJSON_NULL:
            break;
        case cJSON_Number:
            if( item->valuedouble - item->valueint > 0.001)//真正的小数
            {
                sprintf(val,"%.1f",item->valuedouble);
            }else{
                if( item->valueint <=99999 )
                sprintf(val,"%d",item->valueint);
            }
            break;
        case cJSON_String:
            sprintf(val,"%.5s",item->valuestring);//节省内存,暂时限定字符数5
            break;
        case cJSON_Array:
            break;
        case cJSON_Object:
            break;
    }
}

//使用CJSON方式 获取天气内容
char JsonDataAnalyze(const char*pdata, _weatherType* ptq)
{   
    cJSON *json;
    cJSON *counts,*data,*numtq,*numfl,*numfx,*sd,*qw;

    ptq->ok=0;
    pdata = strstr((const char*)pdata,":{");
    json=cJSON_Parse(pdata+1);
    if (!json) { printf("\r\nErr:NULL before: [%s]\r\n",cJSON_GetErrorPtr());}
    else
    {
        counts = cJSON_GetObjectItem(json,"counts");
        if( !counts )
        {
            printf("\r\nErr2:counts before: [%s]\r\n",cJSON_GetErrorPtr());
        }else
        {
            if(counts->valueint >0)
            {
                data = cJSON_GetObjectItem(json,"data");
                if( !data ){
                    printf("\r\nErr:3 before: [%s]\r\n",cJSON_GetErrorPtr());
                }else{
                    numtq = cJSON_GetObjectItem(data,"numtq");   _getValue(numtq,ptq->numtq);
                    numfl = cJSON_GetObjectItem(data,"numfl");   _getValue(numfl,ptq->numfl);
                    numfx = cJSON_GetObjectItem(data,"numfx");   _getValue(numfx,ptq->numfx);
                    sd = cJSON_GetObjectItem(data,"sd");         _getValue(sd,ptq->sd);
                    qw = cJSON_GetObjectItem(data,"qw");         _getValue(qw,ptq->qw);
                    ptq->ok = 1;
                }
            }
        }
        cJSON_Delete(json);
    }
    return ptq->ok ;
}

数据内容会有些UTF格式汉字,我使用的串口屏只支持GBK汉字,只是测试所以没有做UTF到GBK的转换,直接使用函数映射相关中文内容。如下:

//注意设置本文档编码方式为GB2312或GBK
//根据编号返回天气状况汉字描述
char* weather_tq_str(char num)
{
    switch(num)
    {
        case 0:return "晴";
        case 1:return "多云";
        case 2:return "阴";
        case 3:return "阵雨";
        case 4:return "雷阵雨";
        case 5:return "雷阵雨伴有冰雹";
        case 6:return "雨夹雪";
        case 7:return "小雨";
        case 8:return "中雨";
        case 9:return "大雨";
        case 10:return "暴雨";
        case 11:return "大暴雨";
        case 12:return "特大暴雨";
        case 13:return "阵雪";
        case 14:return "小雪";
        case 15:return "中雪";
        case 16:return "大雪";
        case 17:return "暴雪";
        case 18:return "雾";
        case 19:return "冻雨";
        case 20:return "沙尘暴";
        case 21:return "小到中雨";
        case 22:return "中到大雨";
        case 23:return "大到暴雨";
        case 24:return "暴雨到大暴雨";
        case 25:return "大暴雨到特大暴雨";
        case 26:return "小到中雪";
        case 27:return "中到大雪";
        case 28:return "大到暴雪";
        case 29:return "浮尘";
        case 30:return "扬沙";
        case 31:return "强沙尘暴";
        case 32:return "浓雾";
        
        case 49:return "强浓雾";
        
        case 53:return "霾";
        case 54:return "中度霾";
        case 55:return "重度霾";
        case 56:return "严重霾";
        case 57:return "大雾";
        case 58:return "特强浓雾";
        
        case 100:return "刮风";
    }
    return "Unknown";
}

//根据编号返回风向汉字描述
char* weather_fx_str(char num)
{
    switch(num)
    {
        case 0:return "无持续风向";
        case 1:return "东北风";
        case 2:return "东风";
        case 3:return "东南风";
        case 4:return "南风";
        case 5:return "西南风";
        case 6:return "西风";
        case 7:return "西北风";
        case 8:return "北风";
        case 9:return "旋转风";

    }
    return "Unknown";
}

6.实际效果

展开阅读全文

没有更多推荐了,返回首页