本文來源電子發(fā)燒友社區(qū),作者:李元江, 帖子地址:https://bbs.elecfans.com/jishu_2025428_1_1.html
元旦好冷,哪也不想去,那就趁著有空,寫寫帖子吧。今天的帖子我寫的是關(guān)于如何從網(wǎng)絡(luò)獲取天氣數(shù)據(jù),以及如何解析出我們需要的天氣數(shù)據(jù)。
-
連接心知天氣服務(wù)器心知天氣服務(wù)器地址為116.62.81.138。端口號為80,連接方式為TCP
-
發(fā)送Get請求成功連接到心知天氣服務(wù)器后,需要發(fā)送Get請求才能獲取到數(shù)據(jù)。我要獲取最近三天的天氣預報情況,請求地址為https://api.seniverse.com/v3/weather/daily.json?key=SgJs9V9ghopE5WSBe&location=shenzhen&language=zh-Hans&unit=c&start=0&days=3則我們需要發(fā)送的數(shù)據(jù)為“Get https://api.seniverse.com/v3/weather/daily.json?key=SgJs9V9ghopE5WSBe&location=shenzhen&language=zh-Hans&unit=c&start=0&days=3rnrn”注意:最后為兩個回車換行。之后會返回天氣數(shù)據(jù)包,但是該數(shù)據(jù)包是Json格式的數(shù)據(jù),需要解析才能得到我們真正需要的數(shù)據(jù)。下面是我使用調(diào)試助手獲取到的數(shù)據(jù)情況。
二、軟件設(shè)計
1、添加cJson功能
從網(wǎng)絡(luò)上直接獲取到的天氣數(shù)據(jù)是Json格式的,需要進行解析才能得到所需天氣數(shù)據(jù)。解析Json格式數(shù)據(jù)我借助第三方軟件包cJson,通過cJson解析出數(shù)據(jù)。其實在wifiiot的例程源代碼中,已經(jīng)添加有cJson了。
但是要使用cJson功能,還需要下面操作。在OLED下的BUILD.gn文件中include_dirs加入 "http://third_party/cJSON",
2、Json數(shù)據(jù)解析
在OLED下面新建從cjsonparse.c和cjsonparse.h文件,主要是關(guān)于Json數(shù)據(jù)解析的函數(shù)。這里我們獲取得天氣數(shù)據(jù)有兩個:實時天氣情況和未來三天天氣數(shù)據(jù)情況,所以需要解析實時天氣Json數(shù)據(jù)和未來三天天氣Json數(shù)據(jù)。
解析實時天氣,主要是為了獲取現(xiàn)在的溫度和天氣情況代碼。
- int cJSON_NowWeatherParse(char *JSON,weather *Weather)
- {
- cJSON *json,*arrayItem,*object,*subobject,*item;
- ?
- json = cJSON_Parse(JSON); //解析JSON數(shù)據(jù)包
- if(json == NULL) //檢測JSON數(shù)據(jù)包是否存在語法上的錯誤,返回NULL表示數(shù)據(jù)包無效
- {
- printf("Error before: [%s]n",cJSON_GetErrorPtr()); //打印數(shù)據(jù)包語法錯誤的位置
- return 1;
- }
- else
- {
- if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL) //匹配字符串"results",獲取數(shù)組內(nèi)容
- {
- cJSON_GetArraySize(arrayItem); //獲取數(shù)組中對象個數(shù)
- //printf("cJSON_GetArraySize: size=%dn",size);
- if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//獲取父對象內(nèi)容
- {
- /* 匹配子對象1 */
- if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
- {
- ?
- }
- /* 匹配子對象2 */
- if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
- {
- printf("---------------------------------now-------------------------------n");
- //匹配子對象2成員"text"
- if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)
- {
- printf("%s : %sn",item->string,item->valuestring);
- }
- //匹配子對象2成員"code"
- if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)
- {
- printf("%s : %sn",item->string,item->valuestring);
- Weather->nowcode = str2int(item->valuestring);
- }
- //匹配子對象2成員"temperature"
- if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL)
- {
- printf("%s : %sn",item->string,item->valuestring);
- Weather->nowtemp = str2int(item->valuestring);
- }
- }
- /* 匹配子對象last_update */
- if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
- {
- printf("----------------------------last_update----------------------------n");
- printf("%s : %snn",subobject->string,subobject->valuestring);
- }
- }
- }
- }
- cJSON_Delete(json); //釋放cJSON_Parse()分配出來的內(nèi)存空間
- return 0;
- }
解析未來三天天氣情況數(shù)據(jù),主要為了獲取今天、明天、后天的最高、最低溫度、天氣情況代碼、濕度情況。當然也可以解析獲取更改天氣情況數(shù)據(jù),但是這里我只解析獲取那么多。
- //解析三天天氣
- int cJSON_TayWeatherParse(char *JSON,weather *weather)
- {
- cJSON *root;
- cJSON *pSub;
- cJSON *arrayItem;
- cJSON *pItem;
- cJSON *pSubItem;
- cJSON *pChildItem;
- cJSON *pLastItem;
- char *pr;
- root = cJSON_Parse((const char*)JSON);
- if(root != NULL)
- {
- pSub = cJSON_GetObjectItem(root,"results");
- if(pSub != NULL)
- {
- arrayItem = cJSON_GetArrayItem(pSub,0);
- pr = cJSON_Print(arrayItem);
- pItem = cJSON_Parse(pr);
- if(pItem != NULL)
- {
- pSubItem = cJSON_GetObjectItem(pItem,"daily");
- if(pSubItem != NULL)
- {
- int size = cJSON_GetArraySize(pSubItem);
- for(int i=0;i;i++)
- {
- if(i==3)break;
- arrayItem = cJSON_GetArrayItem(pSubItem,i);
- pr = cJSON_Print(arrayItem);
- pLastItem = cJSON_Parse(pr);
- if(pLastItem != NULL)
- {
- if((pChildItem =cJSON_GetObjectItem(pLastItem,"high")) != NULL)
- {
- printf("%s : %sn",pChildItem->string,pChildItem->valuestring);
- weather->high[i] = str2int(pChildItem->valuestring);
- }
- ?
- if((pChildItem =cJSON_GetObjectItem(pLastItem,"low")) != NULL)
- {
- printf("%s : %sn",pChildItem->string,pChildItem->valuestring);
- weather->low[i] = str2int(pChildItem->valuestring);
- }
- if((pChildItem =cJSON_GetObjectItem(pLastItem,"code_day"))!=NULL)
- {
- printf("%s : %sn",pChildItem->string,pChildItem->valuestring);
- weather->code[i] = str2int(pChildItem->valuestring);
- }
- if((pChildItem =cJSON_GetObjectItem(pLastItem,"humidity"))!=NULL)
- {
- printf("%s : %sn",pChildItem->string,pChildItem->valuestring);
- weather->humi[i] = str2int(pChildItem->valuestring);
- }
- }
- cJSON_Delete(pLastItem);
- }
- }
- }
- cJSON_Delete(pItem);
- }
- }
- cJSON_Delete(root);
- ?
- return 0;
- }
新建getweather.c文件,主要獲取天氣數(shù)據(jù)的功能函數(shù)。設(shè)置的代碼中主要經(jīng)過如下步驟獲取和解析天氣情況數(shù)據(jù)。
-
1、連接網(wǎng)絡(luò)
-
2、 連接到服務(wù)器
-
3、發(fā)送近三天天氣情況請求
-
4、接收數(shù)據(jù)
-
5、解析近三天天氣Json數(shù)據(jù)
-
6、關(guān)閉與服務(wù)器連接
-
7、從新連接到服務(wù)器
-
8、發(fā)送實時天氣情況請求
-
9、接收數(shù)據(jù)
-
10、解析實時天氣Json數(shù)據(jù)
-
11、關(guān)閉與服務(wù)器連接
-
12、斷開與網(wǎng)絡(luò)的連接
- #include
- #include
- #include
- #include
- ?
- #include "net_demo.h"
- #include "net_common.h"
- #include "net_params.h"
- #include "wifi_connecter.h"
- #include "ohos_init.h"
- #include "cmsis_os2.h"
- #include "cjsonparse.h"
- ?
- #define WEATHERIPADDR "116.62.81.138"
- #define WEATHERPORT 80
- ?
- static char requestday[] = "GET https://api.seniverse.com/v3/weather/daily.json?key=SgJs9V9ghopE5WSBe&location=shenzhen&language=zh-Hans&unit=c&start=0&days=3rnrn";
- static char requestnow[] = "GET https://api.seniverse.com/v3/weather/now.json?key=SgJs9V9ghopE5WSBe&location=shenzhen&language=zh-Hans&unit=crnrn";
- ?
- static char response[1000] = "";
- ?
- weather weatherValue;
- ?
- bool getWeather(void){
- bool sucflag = false;
- WifiDeviceConfig config = {0};
- ?
- // 準備AP的配置參數(shù)
- strcpy(config.ssid, PARAM_HOTSPOT_SSID);
- strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);
- config.securityType = PARAM_HOTSPOT_TYPE;
- osDelay(10);
- int netId = ConnectToHotspot(&config);
- ?
- /*獲取最近三天天氣情況*/
- int32_t retval = 0;
- int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
- struct sockaddr_in serverAddr = {0};
- serverAddr.sin_family = AF_INET;// AF_INET表示IPv4協(xié)議
- serverAddr.sin_port = htons(WEATHERPORT);// 端口號,從主機字節(jié)序轉(zhuǎn)為網(wǎng)絡(luò)字節(jié)序
- if (inet_pton(AF_INET, WEATHERIPADDR, &serverAddr.sin_addr) <= 0) {??// 將主機IP地址從“點分十進制”字符串 轉(zhuǎn)化為 標準格式(32位整數(shù))
- printf("inet_pton failed!rn");
- goto do_cleanup;
- }
- // 嘗試和目標主機建立連接,連接成功會返回0 ,失敗返回 -1
- if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
- printf("connect failed!rn");
- goto do_cleanup;
- }
- printf("connect to server %s success!rn", WEATHERIPADDR);
- ?
- // 建立連接成功之后,這個TCP socket描述符 —— sockfd 就具有了 “連接狀態(tài)”,發(fā)送、接收 對端都是 connect 參數(shù)指定的目標主機和端口
- //retval = send(sockfd, requestnow, sizeof(requestnow), 0);
- retval = send(sockfd, requestday, sizeof(requestday), 0);
- if (retval < 0) {
- printf("send request failed!rn");
- goto do_cleanup;
- }
- printf("send request{%s} %ld to server done!rn", requestday, retval);
- retval = recv(sockfd, &response, sizeof(response), 0);
- if (retval <= 0) {
- printf("send response from server failed or done, %ld!rn", retval);
- goto do_cleanup;
- }
- response[retval] = '';
- int i = 0;
- /*打印接收到數(shù)據(jù)*/
- while(i)
- {
- printf("%c",response[i]);
- i++;
- }
- cJSON_TayWeatherParse(response,&weatherValue);
- close(sockfd);
- ?
- /*獲取現(xiàn)在的天氣情況*/
- sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
- if (inet_pton(AF_INET, WEATHERIPADDR, &serverAddr.sin_addr) <= 0) {??// 將主機IP地址從“點分十進制”字符串 轉(zhuǎn)化為 標準格式(32位整數(shù))
- printf("inet_pton failed!rn");
- goto do_cleanup;
- }
- // 嘗試和目標主機建立連接,連接成功會返回0 ,失敗返回 -1
- if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
- printf("connect failed!rn");
- goto do_cleanup;
- }
- ?
- retval = send(sockfd, requestnow, sizeof(requestnow), 0);
- if (retval < 0) {
- printf("send request failed!rn");
- goto do_cleanup;
- }
- printf("send request{%s} %ld to server done!rn", requestnow, retval);
- retval = recv(sockfd, &response, sizeof(response), 0);
- if (retval <= 0) {
- printf("send response from server failed or done, %ld!rn", retval);
- goto do_cleanup;
- }
- response[retval] = '';
- i = 0;
- /*打印接收到數(shù)據(jù)*/
- while(i)
- {
- printf("%c",response[i]);
- i++;
- }
- cJSON_NowWeatherParse(response,&weatherValue);
- sucflag=true;
- do_cleanup:
- close(sockfd);
- DisconnectWithHotspot(netId);
- if(sucflag)
- return true;
- else
- return false;
- }
把獲取天氣數(shù)據(jù)功能增加到任務(wù)中。在oled_demo.c中static void OledTask(void *arg)函數(shù)增加以下代碼。
- AdcRead(ANALOG_KEY_CHAN_NAME, &data, WIFI_IOT_ADC_EQU_MODEL_4, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0);
- float voltage = ConvertToVoltage(data);
- ?
- if(voltage>0.45 && voltage<0.65)
- {
- OledShowString(16,7,"Sync time...",1);
- getNtpTime();
- OledFillScreen(0);
- }
- else if(voltage>0.9 && voltage<1)
- {
- ?
- OledShowString(0,7,"Get Weather...",1);
- if(getWeather())
- OledFillScreen(0);
- else
- {
- OledShowString(0,7,"Get fail...",1);
- }
- }
按下oled顯示板的右邊按鈕,會進入獲取天氣情況功能。現(xiàn)在我這里只是通過串口打印出來的數(shù)據(jù),觀察數(shù)據(jù)獲取和解析情況,還沒有把解析后的天氣數(shù)據(jù)顯示到oled上。
5、修改BUILD.gn修改OLED文件夾下的BUILD.gn文件,sources中加入getweather.c和cjsonparse.c
- sources = [
- "oled_demo.c",
- "oled_ssd1306.c",
- "timeconv.c",
- "envrionment_demo.c",
- "aht20.c",
- "wifi_connecter.c",
- "getNTP.c",
- "getweather.c",
- "cjsonparse.c",
- ]
三、結(jié)果演示
按下OLED顯示板右邊按鍵,會進入天氣數(shù)據(jù)功能,之后顯示“Get Weather....”提示。天氣數(shù)據(jù)獲取失敗后,會顯示“Get fail...”提示。
可以從串口打印輸出的信息,觀察到獲取的Json數(shù)據(jù)情況和解析后的數(shù)據(jù)情況。
四、總結(jié)
網(wǎng)絡(luò)天氣數(shù)據(jù)的獲取主要經(jīng)過如下步驟
-
連接網(wǎng)絡(luò)
-
連接服務(wù)器
-
請求數(shù)據(jù)
-
解析Json數(shù)據(jù)
2021年第一篇帖子,先寫到這里。下一篇是關(guān)于通過TCP連接與手機APP進行數(shù)據(jù)交互的帖子。當然手機APP是我之前做好的。
-
wi-fi
+關(guān)注
關(guān)注
14文章
2147瀏覽量
124602 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1978瀏覽量
30269 -
HiSpark
+關(guān)注
關(guān)注
1文章
156瀏覽量
6938
發(fā)布評論請先 登錄
相關(guān)推薦
評論