esp32学习笔记:http-request

esp32学习笔记:http-request

在esp-idf中的\examples\protocols\http_server\simple文件夹的例程中简单介绍了esp32作为http客户端请求服务器。

http-request的过程是建立在socket的tcp协议上,通过访问服务器域名的形式来从服务器来获取数据。

大体流程如下:

首先初始化相关硬件,其次连接路由器,最后esp32与服务器建立tcp连接并获取信息。下面内容将介绍相关API。

1 硬件初始化

初始化的硬件主要是NVS,用来保存路由器WIFI的账户信息。还要初始化网络相关的内容。

ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());

2 连接路由器

在esp-idf中中已经封装好连接WIFI的API,其具体如何工作将在以后笔记详述。

ESP_ERROR_CHECK(example_connect());

3 建立TCP连接,并通过http-request获取数据

通过freeRTOS操作系统,创建一个建立数据传输的任务。

xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
3.1 域名解析

服务器通常是以域名的形式给出的,我们需要利用getaddrinfo()函数解析为IP地址。

int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);

WEB_SERVER:服务器域名;WEB_PORT:端口号。

3.2 建立tcp连接

根据解析到的IP地址信息连建立TCP连接。

创建socket s = socket(res->ai_family, res->ai_socktype, 0);

连接服务器 connect(s, res->ai_addr, res->ai_addrlen)

使用write发送get请求 write(s, REQUEST, strlen(REQUEST) 其中REQUEST:是get请求的内容

读取服务器响应数据 read(s, recv_buf, sizeof(recv_buf)-1)

4 连接天气服务器获取数据示例

4.1程序源码
//http组包宏,获取天气的http接口参数
#define WEB_SERVER          "api.seniverse.com"				               
#define WEB_PORT            "80"
#define WEB_URL             "/v3/weather/now.json?key="			
#define APIKEY		        "修改为自己"				     
#define CITY		        "wuxi"
#define LANGUAGE	        "en"

//http请求包

static const char *REQUEST = "GET https://WEB_SERVER/v3/weather/now.json?key=APIKEY&location=CITY&language=LANGUAGE&unit=c\n\n";

static const char *TAG = "example";

//天气解析结构体
typedef struct 
{
    char cit[20];
    char weather_text[20];
    char weather_code[2];
    char temperatur[3];
}weather_info;

weather_info weathe;

void cjson_to_struct_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.cit,"%s",psub->valuestring);
            ESP_LOGI(TAG,"city:%s",weathe.cit);

            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(HTTP_TAG,"%s",weathe.weather_code);

            psub=cJSON_GetObjectItem(now,"temperature");
            sprintf(weathe.temperatur,"%s",psub->valuestring);
            ESP_LOGI(TAG,"temperatur:%s",weathe.temperatur);

            //ESP_LOGI(HTTP_TAG,"--->city %s,weather %s,temperature %s<---\r\n",weathe.cit,weathe.weather_text,weathe.temperatur);
        }
    }
    //ESP_LOGI(HTTP_TAG,"%s 222",__func__);
    cJSON_Delete(root);
}



void https_get_task(void *pvParameters)
{
    const struct addrinfo hints = {
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo *res;
    struct in_addr *addr;
    int s, r;
    char recv_buf[1024];
    char mid_buf[1024];
    int index;
    while(1) {
        
        //DNS域名解析
        int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
        if(err != 0 || res == NULL) {
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p\r\n", err, res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }

        //打印获取的IP
        addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
        //ESP_LOGI(HTTP_TAG, "DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr));

        //新建socket
        s = socket(res->ai_family, res->ai_socktype, 0);
        if(s < 0) {
            ESP_LOGE(TAG, "... Failed to allocate socket.\r\n");
            close(s);
            freeaddrinfo(res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
        //连接ip
        if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
            ESP_LOGE(TAG, "... socket connect failed errno=%d\r\n", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        freeaddrinfo(res);
        //发送http包
        if (write(s, REQUEST, strlen(REQUEST)) < 0) {
            ESP_LOGE(TAG, "... socket send failed\r\n");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        //清缓存
        memset(mid_buf,0,sizeof(mid_buf));
        //获取http应答包
        do {
            bzero(recv_buf, sizeof(recv_buf));
            r = read(s, recv_buf, sizeof(recv_buf)-1);
            strcat(mid_buf,recv_buf);
        } while(r > 0);
        //json解析
        cjson_to_struct_info(mid_buf);
        //关闭socket,http是短连接
        close(s);

        //延时一会
        for(int countdown = 10; countdown >= 0; countdown--) {
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
    }
}


void app_main(void)
{
    ESP_ERROR_CHECK( nvs_flash_init() );
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    ESP_ERROR_CHECK(example_connect());
    xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
}
4.2 实验结果
I (3724) example: city:无锡
I (3724) example: weather:多云
I (3724) example: temperatur:27
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值