ESP8266之HTTP获取天气

模块:esp-01s
SDK版本:ESP8266_RTOS_SDK-3.0
开发环境:wsl+vscode
功能模块:wifi,tcp_client,http_request
本文使用esp8266来获取网络天气,首先我们需要找一个天气的api,例如和风天气,心知天气。关于怎么获取api就不多说了,问度娘吧。
想要从网络获取天气首先我们得联网,然后解析获取天气的地址端口,然后返回数据解析数据。
我分别把连接wifi,和http请求获取天气的函数分别封装出来,连接wifi就不多说了,这里只贴了通过http请求来获取天气的代码。
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <netdb.h>
#include <sys/socket.h>
#include "http_request.h"
#include "tcp_client.h"
#include "wifi.h"

#define WEB_SERVER "example.com"//请求服务器地址
#define WEB_PORT 80//请求端口
#define WEB_URL "https://example.com"//请求url

static const char *TAG = "example";

static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
    "Host: "WEB_SERVER"\r\n"
    "User-Agent: esp-idf/1.0 esp32\r\n"
    "\r\n";

static void http_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;

    while(1) {
        /* Wait for the callback to set the CONNECTED_BIT in the
           event group.
        */
         if(get_wifi_status()==false)  //在此处等待,直到有了wifi
        { 
           vTaskDelay(1000 / portTICK_PERIOD_MS);
           continue;
        }
        ESP_LOGI(TAG, "Connected to AP");
        int err = getaddrinfo(WEB_SERVER, "80", &hints, &res);

        if(err != 0 || res == NULL) {
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }

        /* Code to print the resolved IP.

           Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
        addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));

        s = socket(res->ai_family, res->ai_socktype, 0);
        if(s < 0) {
            ESP_LOGE(TAG, "... Failed to allocate socket.");
            freeaddrinfo(res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... allocated socket");

        if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
            ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }

        ESP_LOGI(TAG, "... connected");
        freeaddrinfo(res);

        if (write(s, REQUEST, strlen(REQUEST)) < 0) {
            ESP_LOGE(TAG, "... socket send failed");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... socket send success");

        struct timeval receiving_timeout;
        receiving_timeout.tv_sec = 5;
        receiving_timeout.tv_usec = 0;
        if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,
                sizeof(receiving_timeout)) < 0) {
            ESP_LOGE(TAG, "... failed to set socket receiving timeout");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... set socket receiving timeout success");

        /* Read HTTP response */
        do {
            bzero(recv_buf, sizeof(recv_buf));
            r = read(s, recv_buf, sizeof(recv_buf)-1);
            for(int i = 0; i < r; i++) {
                putchar(recv_buf[i]);
            }
            SendString(recv_buf);
        } while(r > 0);

        ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d\r\n", r, 
errno);
        close(s);
      
    }
}
void http_start()
{
  xTaskCreate(&http_get_task, "http_get_task", 16384, NULL, 5, NULL);
}

本文链接:

https://www.veryxs.com/index.php/archives/9/
1 + 3 =
2 评论
    1Windows 10
    2020年01月28日 回复

    你这也没把数据解析出来吧 只是获取到返回的数据

      fswEdge 18Windows 10
      2020年02月03日 回复

      @1 没有解析,后来我写了没有贴上来,返回的是json字符串,判断如果读取到了就使用cjson解析,下面是解析部分代码

          if(( r = read(s, recv_buf, sizeof(recv_buf)-1))>0)
          {
               printf("读取到的字节数为:%d\n",r);
      
               char *p=strchr(recv_buf,ch);
              // printf("成功找到:%s",p);
              // memcpy(city,(unsigned char*)p+53,6);
              // printf("城市:%s\n",city);
              vTaskDelay(1000 / portTICK_PERIOD_MS);
              
               printf("获取到的数据:%s\n",p);
              cJSON *pJsonRoot = cJSON_Parse(p);//解析成json格式
               if (pJsonRoot !=NULL) 
               {
                   cJSON *pResult = cJSON_GetObjectItem(pJsonRoot, "result");
                   if(pResult)
                   {
                       cJSON *pLocation = cJSON_GetObjectItem(pJsonRoot, "location");
                       if(pLocation)
                       {
                            cJSON *pName = cJSON_GetObjectItem(pJsonRoot, "name");
                            if(pName)
                            {
                                if (cJSON_IsString(pName))
                                os_printf("城市:%s \n", pName->valuestring);
                            }             
      
                       }
                   }
               }
               cJSON_Delete(pJsonRoot);
          }