ESP32 IDF 获取天气信息( 二 )

  • 连接 connect连接时需要用到服务器的信息,而获取天气信息是通过域名的方式获取的,在连接之前,我们需要使用getaddrinfo()函数进行DNS解析
    /* 域名解析 */int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &dns_info);if(err != 0 || dns_info == NULL) {ESP_LOGE(TAG, "DNS lookup failed err=%d dns_info=%p", err, dns_info);return false;}/* 连接服务器 */if(connect(socket_handle, dns_info->ai_addr, dns_info->ai_addrlen) != 0) {ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);close(socket_handle);freeaddrinfo(dns_info);false;}
  • 通过写数据,发送get请求
    /* 想缓冲区中写入服务请求信息 */if (write(socket_handle, REQUEST, strlen(REQUEST)) < 0) {ESP_LOGE(TAG, "... socket send failed");close(socket_handle);false;}
  • 设置请求超时
    /* 设置请求超时 */struct timeval receiving_timeout;receiving_timeout.tv_sec = 5;receiving_timeout.tv_usec = 0;if (setsockopt(socket_handle, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout, sizeof(receiving_timeout)) < 0){ESP_LOGE(TAG, "... failed to set socket receiving timeout");close(socket_handle);false;}
  • 通过读取数据,获取get响应数据
    bzero(weather_buf, buf_size);// 将内存 weather_buf 前的 sizeof(weather_buf) 全部设置为0int read_size = read(socket_handle, weather_buf, buf_size-1);// 从缓冲区中读取指定长度的数据,当缓冲区中内容小于指定长度时,read() 返回实际读取的数据长度,ESP_LOGI(TAG, "get weather is:%s", weather_buf);// 打印获取的天气信息
  • 四、天气获取案例#include "lvgl_weather_view.h"#include "cJSON.h"#include "../../wifi/wifi.h"#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"/* 获取天气的地址 */#define WEB_SERVER "api.seniverse.com"// 服务器域名#define WEB_PORT "80"// 服务器端口#define WEB_PATH "https://api.seniverse.com/v3/weather/daily.json?key=xxxxxx=Guiyang&language=zh-Hans"// 天气获取路径 /* 存放json解析后的天气信息 */static lvgl_user_weather_info_t user_weather_info = {0};static const char *REQUEST = "GET " WEB_PATH " HTTP/1.0\r\n""Host: "WEB_SERVER":"WEB_PORT"\r\n""User-Agent: esp-idf/1.0 esp32\r\n""\r\n";/** * @brief 获取天气数据 * * @param weather_buf 天气数据的存储空间 * @param buf_size 存储空间的大小 * @return true 获取成功 * @return false 获取失败 */static bool get_weather_buf(char *weather_buf, size_t buf_size){const struct addrinfo hints = {.ai_family = AF_INET,// AF_INET表示IPv4,AF_INET6表示IPv6.ai_socktype = SOCK_STREAM,// SOCK_STREAM表示TCP、SOCK_DGRAM表示UDP、SOCK_RAW表示RAW};struct addrinfo *dns_info;// DNS 解析信息int socket_handle;// socket句柄/* 域名解析 */int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &dns_info);if(err != 0 || dns_info == NULL) {ESP_LOGE(TAG, "DNS lookup failed err=%d dns_info=%p", err, dns_info);return false;}/* 打印解析的服务器 IP */struct in_addr *service_IP = &((struct sockaddr_in *)dns_info->ai_addr)->sin_addr;ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*service_IP));/* 创建套接字 */socket_handle = socket(dns_info->ai_family, dns_info->ai_socktype, 0);// 0(IPPROTO_IP)可以用来表示选择一个默认的协议 。if(socket_handle < 0) {ESP_LOGE(TAG, "... Failed to allocate socket");close(socket_handle);freeaddrinfo(dns_info);false;}// ESP_LOGI(TAG, "allocated socket... ");/* 连接服务器 */if(connect(socket_handle, dns_info->ai_addr, dns_info->ai_addrlen) != 0) {ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);close(socket_handle);freeaddrinfo(dns_info);false;}// ESP_LOGI(TAG, "... connected");/* 释放 dns_info 指向的空间 */freeaddrinfo(dns_info);/* 想缓冲区中写入服务请求信息 */if (write(socket_handle, REQUEST, strlen(REQUEST)) < 0) {ESP_LOGE(TAG, "... socket send failed");close(socket_handle);false;}// ESP_LOGI(TAG, "... socket send success");/* 设置请求超时 */struct timeval receiving_timeout;receiving_timeout.tv_sec = 5;receiving_timeout.tv_usec = 0;if (setsockopt(socket_handle, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout, sizeof(receiving_timeout)) < 0){ESP_LOGE(TAG, "... failed to set socket receiving timeout");close(socket_handle);false;}// ESP_LOGI(TAG, "... set socket receiving timeout success");/* 从缓冲区中读取天气信息 */bzero(weather_buf, buf_size);// 将内存 weather_buf 前的 sizeof(weather_buf) 全部设置为0int read_size = read(socket_handle, weather_buf, buf_size-1);// 从缓冲区中读取指定长度的数据,当缓冲区中内容小于指定长度时,read() 返回实际读取的数据长度,ESP_LOGI(TAG, "get weather is:%s", weather_buf);// 打印获取的天气信息ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", read_size, errno);// 打印读取到的数据长度close(socket_handle);return true;}

    经验总结扩展阅读