ESP32-网络编程-WiFi连接&&https请求(基于espidf && vscode)

前缀

在某招聘网站上看到的esp32网络编程入门面试题。

一、实现功能

  • 启动后连接WIFI,WIFI账号密码分别为"UPGRADE_AP",“TEST1234”,你可以用手机热点的方式模拟WIFI账号密码
  • 连接上WIFI后,访问URL:https://dummyjson.com/products/1 获取其中字段 “brand” 的值,并使用 ESP_LOGI 或者其他输出函数输出到调试终端(串口)
  • 关闭WIFI
额外要求:
  • 使用一个动态分配的内存来存储URL获取的内容,并妥善处理善后。

二、实现过程

2.1Wi-Fi连接部分

  • 初始化nvs分区
ESP_ERROR_CHECK(nvs_flash_init());
  • 初始化WiFi网络接口
ESP_ERROR_CHECK(esp_netif_init());
  • 初始化系统任务函数和Wi-Fi事件处理
//创建默认事件循环。
ESP_ERROR_CHECK(esp_event_loop_create_default());
// 创建STA类型的网卡。
esp_netif_create_default_wifi_sta();
  • 初始化WiFi设置默认值
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
  • 注册WiFi事件回调任务
//获取wifi事件中的任何事件
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT,
                                            ESP_EVENT_ANY_ID,
                                            &event_handler,
                                            NULL) );
//获取ip地址事件
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT,
                                            IP_EVENT_STA_GOT_IP,
                                            &event_handler,
                                            NULL) );
  • 配置STA的相关参数及启动WiFi
wifi_config_t wifi_config={
	.sta={
		.ssid = "UPGRADE_AP",
		.password = "TEST1234"
	}
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
//启动wifi,将会启动wifi回调事件函数 ’event_handler‘
ESP_ERROR_CHECK(esp_wifi_start() );
  • WiFi回调函数event_handler
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) {
    	//断开连接后重连次数
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP...");
        }
        else
        {
            ESP_LOGI(TAG,"connect to the AP fail");
            //xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
        }
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_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(wifi_event_group, WIFI_CONNECTED_BIT);
           }
    else{
        printf("%s,%d\r\n",event_base,event_id);
    }
}

2.2https请求部分

​ 在ESP32的官方例程中是提供有关https request 例程,具体位置在esp-idf中examples下protocols\http_server\simple文件夹中,该例程简单演示了espidf多种方式使用esp32作为http客户端请求服务器。

  • https_get_request_using_crt_bundle主要使用crt_bundle_attach方式,该方式是ESP x509 证书捆绑包 API 提供了一种简单的方法来包含用于 TLS 服务器验证的自定义 x509 根证书捆绑包。捆绑包主要过menuconfig配置完成的,然后通过cmake生成捆绑包并将其嵌入。
#define http_url "https://dummyjson.com/products/1"
static const char HOWSMYSSL_REQUEST[] = "GET https://dummyjson.com/products/1 HTTP/1.1\r\n"
                             "Host: dummyjson.com\r\n"
                             "User-Agent: esp-idf/1.0 esp32\r\n"
                             "\r\n";
static void https_get_request_using_crt_bundle(void)
{
    ESP_LOGI(TAG, "https_request using crt bundle");
    esp_tls_cfg_t cfg = {
        .crt_bundle_attach = esp_crt_bundle_attach,
    };
    https_get_request(cfg, http_url, HOWSMYSSL_REQUEST);
}
  • 参考例程https_get_request函数进行修改,将接收到的数据进行处理ProcessFunc(buf,len)
static void https_get_request(esp_tls_cfg_t cfg, const char *WEB_SERVER_URL, const char *REQUEST)
{
    char buf[4096];
    int ret, len;
    struct esp_tls *tls = esp_tls_conn_http_new(WEB_SERVER_URL, &cfg);

    if (tls != NULL) {
        ESP_LOGI(TAG, "Connection established...");
    } else {
        ESP_LOGE(TAG, "Connection failed...");
        goto exit;
    }
    size_t written_bytes = 0;
    do {
        ret = esp_tls_conn_write(tls,
                                 REQUEST + written_bytes,
                                 strlen(REQUEST) - written_bytes);
        if (ret >= 0) {
            ESP_LOGI(TAG, "%d bytes written", ret);
            written_bytes += ret;
        } else if (ret != ESP_TLS_ERR_SSL_WANT_READ  && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
            ESP_LOGE(TAG, "esp_tls_conn_write  returned: [0x%02X](%s)", ret, esp_err_to_name(ret));
            goto exit;
        }
    } while (written_bytes < strlen(REQUEST));
    ESP_LOGI(TAG, "Reading HTTPS response...");
    do {
        len = sizeof(buf) - 1;
        bzero(buf, sizeof(buf));
        ret = esp_tls_conn_read(tls, (char *)buf, len);
        if (ret == ESP_TLS_ERR_SSL_WANT_WRITE  || ret == ESP_TLS_ERR_SSL_WANT_READ) {
            continue;
        }
        if (ret < 0) {
            ESP_LOGI(TAG, "esp_tls_conn_read  returned [-0x%02X](%s)", -ret, esp_err_to_name(ret));
            break;
        }
        if (ret == 0) {
            ESP_LOGI(TAG, "connection closed");
            break;
        }
        len = ret;
        ESP_LOGI(TAG, "%d bytes read", len);
        //处理接收数据函数
        ProcessFunc(buf,len);
        break; //
        /* Print response directly to stdout as it is read */

    } while (0);

//关闭
exit:
    esp_tls_conn_delete(tls);
    for (int countdown = 1; countdown >= 0; countdown--) {
        // ESP_LOGI(TAG, "%d...", countdown);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

- ProcessFunc(buf,len)处理数据,发现返回数据为json格式且带有相应标头等数据

{	"id":1,
	"title":"iPhone 9",
	"description":"An apple mobile which is nothing like apple",
	"price":549,
	"discountPercentage":12.96,
	"rating":4.69,
	"stock":94,
	"brand":"Apple",
	"category":"smartphones",
	"thumbnail":"https://i.dummyjson.com/data/products/1/thumbnail.jpg",
	"images":[
		"https://i.dummyjson.com/data/products/1/1.jpg",
		"https://i.dummyjson.com/data/products/1/2.jpg",
		"https://i.dummyjson.com/data/products/1/3.jpg",
		"https://i.dummyjson.com/data/products/1/4.jpg",
		"https://i.dummyjson.com/data/products/1/thumbnail.jpg"
		]
}
static void ProcessFunc(char *buf,int len)
{
    //过滤掉无用数据,保留json部分内容
    int i,rev_len;
    for ( i = 0; i < len; i++)
    {
        /* code */
        if(buf[i]=='{')
            break;
    }
    rev_len = len - i + 1;
    char * rev_buf = (char *)malloc(rev_len*sizeof(char));
    memcpy(rev_buf,buf + i,rev_len);
    printf("rev:%s\r\n",rev_buf);
    //json解析
    cJSON* cjson_body = NULL;
    cJSON* cjson_brand = NULL;
    cjson_body = cJSON_Parse(rev_buf);
    if(cjson_body == NULL)
    {
        printf("cjson_body parse fail.\n");
        return ;
    }
    cjson_brand = cJSON_GetObjectItem(cjson_body, "brand");
    if(cjson_brand == NULL)
    {
        printf("cjson_brand parse fail.\n");
        return ;
    }
    ESP_LOGI("brand","%s",cjson_brand->valuestring);
    // printf("brand: %s\n", cjson_brand->valuestring);
    //释放资源
    cJSON_Delete(cjson_body);
    free(rev_buf);
    rev_buf = NULL;
}
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值