1.要获取天气信息,先申请心知天气的密钥。
申请账号后,可以【产品管理】->【基本信息】->【API密钥中】获取到密钥信息:
公钥:
Ppvt4nzay1unX37MZ
私钥:
S_RKZUhKg1LNhfVqa
2.获取时间可以使用苏宁时间提供的API接口:
3.获取B站粉丝数可以使用B站提供的接口:(其中自己的B站UID号为:268521649)
调试这个项目可以说是有史以来遇到的最有挑战性的项目。
按部就班烧录好代码后,编译一次通过,还是很开心的,就是在实际调试的时候发现:
城市数据和时间数据都可以正常获取;天气数据和B站粉丝数据就获取不到,并且会报以下错误:
经过ESP32学习记录 HTTP Client_esp-tls-mbedtls: no server verification option set-CSDN博客的帮助,解决了这个问题,其实就是访问http数据的证书认证问题。解决步骤如下图所示:
通过以上解决方法,解决了访问证书认证的问题。但是在实际调试时,发现天气数据可以正常访问了,但是B站粉丝数数据一直更新不了。通过信息打印bug,可以发现是因为请求B站数据时,收到的数据产生了分包现象,所以导致无法识别。最后调试了一天,通过对分包数据的整合数据包来实现数据帧的完整识别。运行示例如下图所示:
源代码参考:
qy_http_client.h
#ifndef _QY_HTTP_CLIENT_H_
#define _QY_HTTP_CLIENT_H_
typedef enum{
HTTP_GET_TIME = 0,
HTTP_GET_WEATHER = 0,
HTTP_GET_FANS = 0,
HTTP_GET_CITY = 0,
}HTTP_GET_TYPE_E;
typedef struct
{
HTTP_GET_TYPE_E type;
}HTTP_GET_EVENT_T;
void qy_http_request_init(void);
#endif
qy_http_client.c
/* HTTP GET Example using plain POSIX sockets
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "esp_netif.h"
#include "esp_tls.h"
#include "esp_http_client.h"
#include "cJSON.h"
#include "qy_http_client.h"
static const char *TAG = "HTTP_CLIENT";
int fans_type = 0;
/*
{
"sysTime2":"2022-07-10 10:12:43",
"sysTime1":"20220710101243"
}
*/
static void cjson_time_info(char *text)
{
cJSON *root,*psub;
char time[20];
//截取有效json
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root!=NULL)
{
psub = cJSON_GetObjectItem(root, "sysTime1");
sprintf(time,"%s",psub->valuestring);
ESP_LOGI(TAG,"sysTime:%s",time);
}
cJSON_Delete(root);
int len = strlen(time);
if(len < 11){
return;
}
// uint8_t hour;
// uint8_t minute;
// hour = (time[8] - '0')*10+time[9] - '0';
// minute = (time[10] - '0')*10+time[11] - '0';
}
//天气解析结构体
typedef struct
{
char city[20];
char weather_text[20];
char weather_code[2];
char temperatur[3];
}weather_info;
weather_info weathe;
/*
{
"results":[
{
"location":{
"id":"WS0E9D8WN298",
"name":"广州",
"country":"CN",
"path":"广州,广州,广东,中国",
"timezone":"Asia/Shanghai",
"timezone_offset":"+08:00"
},
"now":{
"text":"多云",
"code":"4",
"temperature":"31"
},
"last_update":"2022-07-10T11:00:02+08:00"
}
]
}
*/
void cjson_weather_info(char *text)
{
cJSON *root,*psub;
cJSON *arrayItem;
//截取有效json
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root!=NULL)
{
psub = cJSON_GetObjectItem(root, "results");
arrayItem = cJSON_GetArrayItem(psub,0);
cJSON *locat = cJSON_GetObjectItem(arrayItem, "location");
cJSON *now = cJSON_GetObjectItem(arrayItem, "now");
if((locat!=NULL)&&(now!=NULL))
{
psub=cJSON_GetObjectItem(locat,"name");
sprintf(weathe.city,"%s",psub->valuestring);
ESP_LOGI(TAG,"city:%s",weathe.city);
psub=cJSON_GetObjectItem(now,"text");
sprintf(weathe.weather_text,"%s",psub->valuestring);
ESP_LOGI(TAG,"weather:%s",weathe.weather_text);
psub=cJSON_GetObjectItem(now,"code");
sprintf(weathe.weather_code,"%s",psub->valuestring);
ESP_LOGI(TAG,"%s",weathe.weather_code);
psub=cJSON_GetObjectItem(now,"temperature");
sprintf(weathe.temperatur,"%s",psub->valuestring);
ESP_LOGI(TAG,"temperatur:%s",weathe.temperatur);
}
}
cJSON_Delete(root);
}
/*
{
"code":0,
"message":"0",
"ttl":1,
"data":{
"mid":383943678,
"following":13,
"whisper":0,
"black":0,
"follower":14233
}
}
*/
void cjson_fans_info(char *text)
{
cJSON *root,*psub,*ppsub;
int fans = 0;
//截取有效json
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root != NULL)
{
psub = cJSON_GetObjectItem(root, "data");
if(psub != NULL)
{
ESP_LOGI(TAG,"钱忆调试信息20230201!");
ppsub = cJSON_GetObjectItem(psub, "follower");
if(ppsub != NULL){
fans = ppsub->valueint;
ESP_LOGI(TAG,"fans:%d",fans);
}
}
}
cJSON_Delete(root);
}
/*
{
"cip":"121.32.92.51",
"cid":"440106",
"cname":"广东省广州市天河区"
}
*/
static void cjson_city_info(char *text)
{
cJSON *root,*psub;
char name[20];
char cid[20];
//截取有效json
char *index=strchr(text,'{');
strcpy(text,index);
root = cJSON_Parse(text);
if(root!=NULL)
{
psub = cJSON_GetObjectItem(root, "cname");
sprintf(name,"%s",psub->valuestring);
ESP_LOGI(TAG,"name:%s",name);
psub = cJSON_GetObjectItem(root, "cid");
sprintf(cid,"%s",psub->valuestring);
ESP_LOGI(TAG,"cid:%s",cid);
}
cJSON_Delete(root);
}
//事件回调
static esp_err_t _http_time_event_handle(esp_http_client_event_t *evt)
{
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA://接收数据事件
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
printf("%.*s\n", evt->data_len, (char*)evt->data);
if(evt->data_len < 100)
cjson_time_info((char*)evt->data);
}
break;
case HTTP_EVENT_ERROR:
break;
case HTTP_EVENT_ON_CONNECTED:
break;
case HTTP_EVENT_HEADERS_SENT:
break;
case HTTP_EVENT_ON_HEADER:
break;
case HTTP_EVENT_DISCONNECTED:
break;
case HTTP_EVENT_ON_FINISH:
break;
}
return ESP_OK;
}
static esp_err_t _http_weather_event_handle(esp_http_client_event_t *evt)
{
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA://接收数据事件
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
printf("%.*s\n", evt->data_len, (char*)evt->data);
cjson_weather_info((char*)evt->data);
}
break;
case HTTP_EVENT_ERROR:
break;
case HTTP_EVENT_ON_CONNECTED:
break;
case HTTP_EVENT_HEADERS_SENT:
break;
case HTTP_EVENT_ON_HEADER:
break;
case HTTP_EVENT_DISCONNECTED:
break;
case HTTP_EVENT_ON_FINISH:
break;
}
return ESP_OK;
}
char qianyi_debug[200] = {0};
static esp_err_t _http_fans_event_handle(esp_http_client_event_t *evt)
{
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA://接收数据事件
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
printf("%.*s\n", evt->data_len, (char*)evt->data);
// cjson_fans_info((char*)evt->data);
memcpy(&(qianyi_debug[strlen(qianyi_debug)]), evt->data, evt->data_len);
}
break;
case HTTP_EVENT_ERROR:
break;
case HTTP_EVENT_ON_CONNECTED:
break;
case HTTP_EVENT_HEADERS_SENT:
break;
case HTTP_EVENT_ON_HEADER:
break;
case HTTP_EVENT_DISCONNECTED:
break;
case HTTP_EVENT_ON_FINISH:
break;
}
return ESP_OK;
}
static esp_err_t _http_city_event_handle(esp_http_client_event_t *evt)
{
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA://接收数据事件
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
printf("%.*s\n", evt->data_len, (char*)evt->data);
cjson_city_info((char*)evt->data);
}
break;
case HTTP_EVENT_ERROR:
break;
case HTTP_EVENT_ON_CONNECTED:
break;
case HTTP_EVENT_HEADERS_SENT:
break;
case HTTP_EVENT_ON_HEADER:
break;
case HTTP_EVENT_DISCONNECTED:
break;
case HTTP_EVENT_ON_FINISH:
break;
}
return ESP_OK;
}
void http_time_get(){
//http client配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET, //get请求
.url = "http://quan.suning.com/getSysTime.do",
.event_handler = _http_time_event_handle,//注册时间回调
.skip_cert_common_name_check = true,
};
esp_http_client_handle_t time_client = esp_http_client_init(&config);//初始化配置
esp_err_t err = esp_http_client_perform(time_client);//执行请求
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Status = %d, content_length = %d",
esp_http_client_get_status_code(time_client),//状态码
esp_http_client_get_content_length(time_client));//数据长度
}
esp_http_client_cleanup(time_client);//断开并释放资源
}
void http_weather_get(){
//http client配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET, //get请求
.url = "https://api.seniverse.com/v3/weather/now.json?key=S_RKZUhKg1LNhfVqa&location=nanjing&language=zh-Hans&unit=c",
.event_handler = _http_weather_event_handle,//注册时间回调
.skip_cert_common_name_check = true,
};
esp_http_client_handle_t weather_client = esp_http_client_init(&config);//初始化配置
esp_err_t err = esp_http_client_perform(weather_client);//执行请求
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Status = %d, content_length = %d",
esp_http_client_get_status_code(weather_client),//状态码
esp_http_client_get_content_length(weather_client));//数据长度
}
esp_http_client_cleanup(weather_client);//断开并释放资源
}
void http_fans_get(){
//http client配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET, //get请求
.url = "https://api.bilibili.com/x/relation/stat?vmid=268521649&jsonp=jsonp",
.event_handler = _http_fans_event_handle,//注册时间回调
.skip_cert_common_name_check = true,
};
esp_http_client_handle_t fans_client = esp_http_client_init(&config);//初始化配置
esp_err_t err = esp_http_client_perform(fans_client);//执行请求
if(err == ESP_OK)
{
printf("%.*s\n", strlen(qianyi_debug), qianyi_debug);
ESP_LOGI(TAG, "qianyi_debug_length = %d", strlen(qianyi_debug));
cjson_fans_info(qianyi_debug);
memset(qianyi_debug, 0, strlen(qianyi_debug));
ESP_LOGI(TAG, "Status = %d, content_length = %d",
esp_http_client_get_status_code(fans_client),//状态码
esp_http_client_get_content_length(fans_client));//数据长度
}
esp_http_client_cleanup(fans_client);//断开并释放资源
}
void http_city_get(){
//http client配置
esp_http_client_config_t config = {
.method = HTTP_METHOD_GET, //get请求
.url = "http://pv.sohu.com/cityjson?ie=utf-8", //请求url
.event_handler = _http_city_event_handle,//注册时间回调
.skip_cert_common_name_check = true,
};
esp_http_client_handle_t city_client = esp_http_client_init(&config);//初始化配置
esp_err_t err = esp_http_client_perform(city_client);//执行请求
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Status = %d, content_length = %d",
esp_http_client_get_status_code(city_client),//状态码
esp_http_client_get_content_length(city_client));//数据长度
}
esp_http_client_cleanup(city_client);//断开并释放资源
}
void qy_http_post(void)
{
// //http client配置
// esp_http_client_config_t config = {
// .method = HTTP_METHOD_GET, //get请求
// .url = "http://quan.suning.com/getSysTime.do",
// .event_handler = _http_event_handle,//注册时间回调
// .skip_cert_common_name_check = true,
// };
// // // POST
// // const char *post_data = "field1=value1&field2=value2";
// // esp_http_client_set_url(client, "http://httpbin.org/post");
// // esp_http_client_set_method(client, HTTP_METHOD_POST);
// // esp_http_client_set_post_field(client, post_data, strlen(post_data));
// // int err = esp_http_client_perform(client);
// // if (err == ESP_OK) {
// // ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
// // esp_http_client_get_status_code(client),
// // esp_http_client_get_content_length(client));
// // int len = esp_http_client_get_content_length(client);
// // int read_len = 0;
// // char buf[1024] = {0};
// // read_len = esp_http_client_read(client, buf, len);
// // printf("\nrecv data len:%d %d %s\n",read_len,len,buf);
// // } else {
// // ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
// // }
// esp_http_client_cleanup(client);
}
xQueueHandle http_get_event_queue;
void qy_http_set_type(HTTP_GET_TYPE_E type){
HTTP_GET_EVENT_T evt;
evt.type = type;
xQueueSend(http_get_event_queue, &evt, 10);
}
static void http_get_task(void *pvParameters)
{
while(1) {
http_fans_get();
// HTTP_GET_EVENT_T evt;
// xQueueReceive(http_get_event_queue, &evt, portMAX_DELAY);
// ESP_LOGI(TAG, "http_get_task %d",evt.type);
// vTaskDelay(1000 / portTICK_PERIOD_MS);
// if(evt.type == HTTP_GET_TIME){
// http_time_get();
// }else if(evt.type == HTTP_GET_WEATHER){
// http_weather_get();
// }else if(evt.type == HTTP_GET_FANS){
// http_fans_get();
// }else if(evt.type == HTTP_GET_CITY){
// http_city_get();
// }
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}
void qy_http_request_init(void)
{
http_get_event_queue = xQueueCreate(10, sizeof(HTTP_GET_EVENT_T));
xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, NULL);
}
main函数:
#include "qy_oled.h"
#include "qy_wifi_ap.h"
#include "ds_nvs.h"
#include "qy_http_server.h"
#include "ds_system_data.h"
#include "qy_wifi_sta.h"
#include "qy_wifi_scan.h"
#include "qy_http_client.h"
char *ssid="qianyi";
char *psw="12345678";
void app_main(void)
{
LCD_Init();
ds_system_data_init();
set_system_data_wifi_info(ssid,strlen(ssid),psw,strlen(psw));
ds_nvs_init();
LCD_FullClean(WHITE);
// qy_wifi_ap_start();
// qy_http_server_init();
qy_wifi_sta_start();
// qy_wifi_scan_start();
qy_http_request_init();
while(1){
printf("system run ...\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}