最近在用esp8266獲取天氣預報時,遇到了許多問題,經過了一下午的蒐羅,總結出以下經驗供各位網友學習。
本文只需通曉8266連接wifi,創建tcp連接即可。
我使用的是心知天氣的api,百度搜索即可,可以申請免費試用付費版也可以使用免費版,這裏以免費版爲例。
心知天氣api:https://api.seniverse.com/v3/weather/now.json?key=key&location=beijing&language=zh-Hans&unit=c
當你註冊好心知天氣的賬號並開通免費版或者申請試用後或獲得一個密鑰,將連接中的加粗字體key替換爲你的密鑰即可。
PS:
鏈接中加粗字體beijing爲地區名,想換成哪裏就是哪裏的拼音。
鏈接中加粗字體zh-Hans爲語言,如果想代碼簡單化就改成en,英文方式顯示,中文處理過於複雜,本文即爲在英語環境下處理
首先我們來看下本文程序思想:
1.連接WIFI
2.DNS解析域名獲得IP
3.創建TCP連接
4.GET獲得源代碼
5.數據處理
1.連接WIFI
本步驟過於簡單,不再贅述。
2.DNS解析域名獲得IP
8266官方庫中給出了espconn_gethostbyname()這樣的一個函數,可以解析域名獲得IP,但本人覺得放在8266中運行無疑是增加了負擔,這一步完全可以通過PC端完成,本文便以最簡便方式說明。
步驟:win+r鍵→輸入cmd→輸入ping api.seniverse.com並回車
文中紅框便爲心知天氣IP地址,此處注意域名前面千萬不要加http://或https://
3.創建TCP連接
本步驟過於簡單,不再贅述。
但要提一下的是創建TCP連接時,IP爲上面取到的IP,端口則爲80。
4.GET獲得源代碼
如想獲取源代碼,便需要以下知識。
客戶端發送一個HTTP請求到服務器的請求消息包括以下格式:
請求行(request line)、請求頭部(header)、空行和請求數據四個部分組成,下圖給出了請求報文的一般格式。
而我們這次用的方法是GET,URL是:/v3/weather/now.json?key=Key&location=beijing&language=zh-Hans&unit=c,Key注意替換,協議版本是HTTP/1.1,HOST是api.seniverse.com,剩下的我們並不需要,再加上請求報文一般格式上的符號,代碼如下:
//要獲取網站的網址
#define HOST "api.seniverse.com"
/*二下兩個請求頭都是可以使用,第二個請求頭使用了最少的報文頭
*請求頭由幾個部分組成:<請求方法> <請求URL> <請求協議版本>\r\n<報文頭>\r\n\r\n
*/
#define HEAD "GET /v3/weather/now.json?key=Key&location=shijiazhuang&language=en&unit=c HTTP/1.1\r\nHost: %s\r\n\r\n"
然後在TCP連接成功回調函數中,發送此字符串,以數組形式保存。
此時服務器會返回我們json格式的數據,在TCP接收到數據回調函數內執行之後的代碼:
5.數據處理
我們收到的數據會是這樣的:
{"results":[{"location":{"id":"WWC2MYYCM6J5","name":"Shijiazhuang","country":"CN","path":"Shijiazhuang,Shijiazhuang,Hebei,China","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"text":"Cloudy","code":"4","temperature":"26"},"last_update":"2019-05-15T19:45:00+08:00"}]}
u8 Buffer[]={0};
void ICACHE_FLASH_ATTR user_tcp_recv_cb(void *arg,
char *pdata,
unsigned short len)
{
os_printf("收到數據:%s\r\n",pdata);//將收到的json格式數據串口輸出
char *p=strstr(pdata,"code");//查找code首次出現的地址並賦值給指針p
p+=7;//p+7跳轉到code的數據 code爲天氣數據
os_printf("收到:%s\r\n",p);//將code的數據及之後的json格式數據串口輸出
strncpy(Buffer,p,1);//將code的數據放到Buffer裏
os_printf("收到:%s\r\n",Buffer);//將Buffer數據打印
p+=18;//跳轉到temperature的數據 temperature爲溫度數據
strncpy(Buffer+2,p,2);//存放到Buffer+2裏
ChooseWeather();//判斷天氣代碼
}
這裏每個數據都用兩個位置存放,因爲不管天氣代碼還是溫度都有兩位數的。
天氣代碼格式參見:https://docs.seniverse.com/api/start/code.html
當我們將兩個數據都放到Buffer數組後,就可以進行條件選擇了。
因爲數組是無符號char型的並非整數並且是放在兩個地方存儲的,我們無法直接進行if判斷,所以要先進行轉換。
這裏博主通過aoti函數進行轉換髮現程序會跑飛,無奈只能自己通過ASCII字符碼錶轉換了,ASCII字符碼錶48——57對應0~9。
代碼如下:
void ChooseWeather()
{
int a,b;
a=Buffer[0]-48;
b=Buffer[1]-48;
if(b<0)//如果b不存在 即天氣代碼爲個位數
{
if(a==0||a==1)//晴天
{
OLED_ShowSChar(16,16,2,5,Sunny);
os_printf("That is ok\r\n");
}
//多雲
else if(a==4||a==5||a==6||a==7||a==8)
{
OLED_ShowSChar(16,16,2,5,Cloudy);
os_printf("That is ok\r\n");
}
else if(a==9)//陰天
{
OLED_ShowSChar(16,16,2,5,weather+32);
}
}
else
{
//雨
if(a==1&&(b==1||b==2||b==3||b==4||b==5||b==6||b==7||b==8||b==9))
{
OLED_ShowSChar(16,16,2,5,Rain);
}
//雨夾雪
else if(a==2&&b==0)
{
OLED_ShowSChar(16,16,2,5,RainSnow);
}
//雪
else if(a==2&&(b==1||b==2||b==3||b==4||b==5))
{
OLED_ShowSChar(16,16,2,5,Snow);
}
//霧霾
else if(a==3&&b==0)
{
OLED_ShowSChar(16,16,2,5,Smog);
}
}
}
至於溫度以及時間這裏不再一一贅述,邏輯都是一樣的,自己參考便可獨立完成,勿做伸手黨!