[学习记录]esp32通过wifi进行http请求获得天气信息

http协议解释

本次使用的开发板为和宙esp32c3,使用的IDE为vscode+espidf
程序整体流程:
[学习记录]esp32通过wifi进行http请求获得天气信息_第1张图片

以下为程序详解

WiFi连接

首先使能nvs,将等下使用的WiFi账号及密码储存到nvs上

NVS介绍:官方介绍比较繁杂。通俗来说,NVS 就是在flash 上分配的一块内存空间 ,提供给用户保存电不丢失的数据

进入主题,我们需要将esp32连接WiFi,此时使用为WIFI STATION模式,下面给出官方步骤
[学习记录]esp32通过wifi进行http请求获得天气信息_第2张图片

ESP_ERROR_CHECK(esp_netif_init());                      //01-1 创建LWIP核心任务
ESP_ERROR_CHECK(esp_event_loop_create_default());       //01-2 创建系统事件任务
esp_netif_create_default_wifi_sta();                    //01-3 创建station实例
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));                   //01-4 创建wifi驱动程序任务,并初始化wifi驱动程序
                                                        //01-5 注册,用于处理wifi连接的过程中的事件
esp_event_handler_instance_t instance_any_id;           //用于处理wifi连接时候的事件的句柄
esp_event_handler_instance_t instance_got_ip;           //用于处理ip分配时候产生的事件的句柄
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,   //该句柄对wifi连接所有事件都产生响应,连接到event_handler回调函数
    ESP_EVENT_ANY_ID,
    &event_handler,
    NULL,
    &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,   //该句柄仅仅处理IP_EVENT事件组中的获取ip地址事件,连接到event_handler回调函数
    IP_EVENT_STA_GOT_IP, 
    &event_handler,
    NULL,
    &instance_got_ip));

02 WIFI配置阶段
//02-1 定义wifi配置参数
wifi_config_t wifi_config;                                          //定义wifi配置参数结构体
memset(&wifi_config, 0, sizeof(wifi_config));                       //对结构体进行初始化,把参数全部定义为0
sprintf((char*)wifi_config.sta.ssid, EXAMPLE_ESP_WIFI_SSID);        //配置wifi名称              
sprintf((char*)wifi_config.sta.password, EXAMPLE_ESP_WIFI_PASS);    //配置wifi密码
wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;            //配置加密协议
wifi_config.sta.pmf_cfg.capable = true;                             
wifi_config.sta.pmf_cfg.required = false;
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));                  //02-2 配置wifi工作模式
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));    //02-3 写入配置

//03 wifi启动阶段
//03-1 启动wifi驱动程序
ESP_ERROR_CHECK(esp_wifi_start());   //会触发回调函数
ESP_LOGI(TAG, "wifi_init_sta finished.");

//04 等待wifi连接并输出wifi连接结果   
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
    WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
    pdFALSE,
    pdFALSE,
    portMAX_DELAY);

    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
            EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    }
    else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
            EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    }
    else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }

//05  事件解绑定
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);

下面是WiFi回调函数

static void event_handler(void* arg, esp_event_base_t event_base,
    int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {   //如果是wifi连接事件,就进行wifi连接
        esp_wifi_connect();
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {  //如果是wifi连接失败事件
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {   //如果没有达到最高尝试次数,继续尝试
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        }
        else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);   //如果达到了最高尝试次数,就停止尝试,并且标记连接失败
        }
        ESP_LOGI(TAG, "connect to the AP fail");
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {     //如果是ip获取事件,获取到了ip就打印出来
        ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);    //如果成功获取到了ip,就标记这次wifi连接成功
    }
}

连接服务器并发送请求解析返回数据

使用了esp_http_client库官方介绍

static void http_test_task(void *pvParameters)
{

//02-1 定义需要的变量
    char output_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};   //用于接收通过http协议返回的数据
    int content_length = 0;  //http协议头的长度

    //02-2 配置http结构体
   
   //定义http配置结构体,并且进行清零
    esp_http_client_config_t config ;
    memset(&config,0,sizeof(config));

    //向配置结构体内部写入url
    static const char *URL = "http://api.seniverse.com/v3/weather/now.json?key=SCoom38PWDOGScGYt&location=zhengzhou&language=zh-Hans&unit=c";
    config.url = URL;

    //初始化结构体
    esp_http_client_handle_t client = esp_http_client_init(&config);	//初始化http连接

    //设置发送请求 
    esp_http_client_set_method(client, HTTP_METHOD_GET);

    //02-3 循环通讯

    while(1)
    {

    // 与目标主机创建连接,并且声明写入内容长度为0
    esp_err_t err = esp_http_client_open(client, 0);

    //如果连接失败
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
    } 
    //如果连接成功
    else {

        //读取目标主机的返回内容的协议头
        content_length = esp_http_client_fetch_headers(client);

        //如果协议头长度小于0,说明没有成功读取到
        if (content_length < 0) {
            ESP_LOGE(TAG, "HTTP client fetch headers failed");
        } 

        //如果成功读取到了协议头
        else {
            //读取目标主机通过http的响应内容
            int data_read = esp_http_client_read_response(client, output_buffer, MAX_HTTP_OUTPUT_BUFFER);
            if (data_read >= 0)
            {
            //打印响应内容,包括响应状态,响应体长度及其内容
            ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %lld",
            esp_http_client_get_status_code(client),				//获取响应状态信息
            esp_http_client_get_content_length(client));			//获取响应信息长度
            // printf("data:%s\n", output_buffer);
            //对接收到的数据作相应的处理
            cJSON* root = NULL;
            root = cJSON_Parse(output_buffer);
            if (root == NULL) {
                ESP_LOGE(TAG, "Error parsing JSON data!");
            
            }

            cJSON *results = cJSON_GetObjectItem(root, "results");
            if (results == NULL) {
                ESP_LOGE(TAG, "Failed to get 'results' object!");
                cJSON_Delete(root);
            
            }

            cJSON *location = cJSON_GetObjectItem(results->child, "location");
            if (location == NULL) {
                ESP_LOGE(TAG, "Failed to get 'location' object!");
                cJSON_Delete(root);
                
            }

            cJSON *now = cJSON_GetObjectItem(results->child, "now");
            if (now == NULL) {
                ESP_LOGE(TAG, "Failed to get 'now' object!");
                cJSON_Delete(root);
            
            }

            const char *name = cJSON_GetObjectItem(location, "name")->valuestring;
            const char *text = cJSON_GetObjectItem(now, "text")->valuestring;
            const char *temperature = cJSON_GetObjectItem(now, "temperature")->valuestring;

            ESP_LOGE(TAG, "Location: %s", name);
            ESP_LOGE(TAG, "Weather: %s", text);
            ESP_LOGE(TAG, "Temperature: %s", temperature);
            } 
            //如果不成功
            else {
                ESP_LOGE(TAG, "Failed to read response");
            }
        }
    }

    //关闭连接
    esp_http_client_close(client);

    //延时,因为心知天气免费版本每分钟只能获取20次数据
    vTaskDelay(3000/portTICK_PERIOD_MS);

    }

}

简单记录下,物联网刚刚入门各种协议还不明白暂时说不清楚。
关于http协议的,补充完知识后详细记录

你可能感兴趣的:(学习,http,网络协议)