ESP32学习笔记:HTTP Client获取天气时间B站粉丝数

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);
    }
}

好的,以下是ESP32获取B站粉丝的代码: ```c #include <WiFi.h> #include <HTTPClient.h> #include <ArduinoJson.h> const char* ssid = "your_SSID"; const char* password = "your_PASSWORD"; const char* host = "api.bilibili.com"; const char* endpoint = "/x/relation/stat?vmid=your_UID"; void setup() { Serial.begin(9600); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); } void loop() { if (WiFi.status() == WL_CONNECTED) { HTTPClient http; Serial.print("Connecting to host: "); Serial.println(host); http.begin(host, 80, endpoint); int httpCode = http.GET(); if (httpCode > 0) { String payload = http.getString(); Serial.println(payload); DynamicJsonDocument doc(1024); deserializeJson(doc, payload); int followerCount = doc["data"]["follower"].as<int>(); Serial.print("Follower count: "); Serial.println(followerCount); } else { Serial.print("HTTP request failed with code "); Serial.println(httpCode); } http.end(); } delay(60000); // 每分钟更新一次粉丝 } ``` 在这个代码中,我们使用WiFi库连接到WiFi网络,并使用HTTPClient库向B站API发出GET请求,以获取B站用户的粉丝。我们将收到的JSON响应解析为JSON对象,并从中提取粉丝。最后,我们将粉丝打印到串口。此代码每分钟更新一次粉丝。请将“your_SSID”,“your_PASSWORD”和“your_UID”替换为您的WiFi SSID,密码和B站用户ID。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moon2shine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值