【ESP32】-【http获取天气预报】

软件参考:ESP32开发指南目录(开源一小步出品)https://blog.csdn.net/qq_24550925/article/details/85933563

2020-07-29
好久不见,又回来了。重新开始学习。
http获取天气预报

#include 
#include 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "esp_smartconfig.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "cJSON.h"

/*
===========================
宏定义
=========================== 
*/
#define false		0
#define true		1
#define errno		(*__errno())

//http组包宏,获取天气的http接口参数
#define WEB_SERVER          "api.thinkpage.cn"              
#define WEB_PORT            "80"
#define WEB_URL             "/v3/weather/now.json?key="
#define host 		        "api.thinkpage.cn"
#define APIKEY		        "g3egns3yk2ahzb0p"       
#define city		        "suzhou"
#define language	        "en"

/*
===========================
全局变量定义
=========================== 
*/
//http请求包
static const char *REQUEST = "GET "WEB_URL""APIKEY"&location="city"&language="language" HTTP/1.1\r\n"
    "Host: "WEB_SERVER"\r\n"
    "Connection: close\r\n"
    "\r\n";

//wifi链接成功事件
static EventGroupHandle_t wifi_event_group;
//天气解析结构体
typedef struct 
{
    char cit[20];
    char weather_text[20];
    char weather_code[2];
    char temperatur[3];
}weather_info;

weather_info weathe;

static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "sc";
static const char *TAG1 = "u_event";
static const char *HTTP_TAG = "http_task";


void smartconfig_example_task(void *parm);
void http_get_task(void *pvParameters);
static esp_err_t event_handler(void *ctx, system_event_t *event);


#define LED_IO 22

#define KEY_REC_IO      36
#define KEY_MODE_IO     39

uint8_t  key_value = 0;
uint16_t timer_ms_cnt = 0;
uint16_t timer_1s_cnt = 0;
uint8_t  led_flag = 0;
//定时器句柄
esp_timer_handle_t fw_timer_handle = 0;


void read_key(void);
void fw_timer_cb(void *arg);
static void user_app(void *pvParameters);



void app_main()
{
	printf("app_main!\n");
    /* 建议保留此输出打印SDK版本,用于以后出问题了可以有溯源 */
    ESP_LOGI("app_main","the esp32 sdk version :%s\n", esp_get_idf_version());  

   //选择 IO
   gpio_pad_select_gpio(LED_IO);
   gpio_pad_select_gpio(KEY_REC_IO);
   gpio_pad_select_gpio(KEY_MODE_IO);

   //设置 IO 为输出
   gpio_set_direction(LED_IO, GPIO_MODE_OUTPUT);
   gpio_set_level(LED_IO, 1);//不亮

   //设置按键 IO 输入
   gpio_set_direction(KEY_REC_IO, GPIO_MODE_INPUT);
   gpio_set_direction(KEY_MODE_IO, GPIO_MODE_INPUT);

   //定时器结构体初始化
   esp_timer_create_args_t fw_timer =
   {
      .callback = &fw_timer_cb, //回调函数
      .arg = NULL, //参数
      .name = "fw_timer" //定时器名称
   };

   //定时器创建、启动
   esp_err_t err = esp_timer_create(&fw_timer, &fw_timer_handle);
   err = esp_timer_start_periodic(fw_timer_handle, 1 * 1000);//1ms回调
   if(err == ESP_OK)
   {
      printf("fw timer cteate and start ok!\r\n");
   }


    ESP_ERROR_CHECK(nvs_flash_init());
    tcpip_adapter_init();
    //事件组
    wifi_event_group = xEventGroupCreate();
    //注册wifi事件
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
    //wifi设置:默认设置,等待sc配置
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    //sta模式
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    //启动wifi
    ESP_ERROR_CHECK(esp_wifi_start());




    //新建一个app任务
    xTaskCreate(&user_app,       //任务函数名
                "user_app",      //任务名
                2048,               //栈大小,单位为字,即4个字节,设置太小堆栈会溢出
                NULL,               //任务形参
                8,                  //优先级,数值越大,优先级越高
                NULL                //句柄
                );


}




void read_key(void)
{
   static uint8_t cnt1 = 50;
   static uint8_t cnt2 = 50;

   if(gpio_get_level(KEY_REC_IO)==0)//按键按下
      cnt1++;
   else
      cnt1--;
   
   if(gpio_get_level(KEY_MODE_IO)==0)//按键按下
      cnt2++;
   else
      cnt2--;

   if(cnt1 > 52)
   {
      cnt1 = 50;
      key_value |= 0x01;
   }
   else if(cnt1 < 48)
   {
      cnt1 = 50;
      key_value &= ~0x01;
   }

   if(cnt2 > 52)
   {
      cnt2 = 50;
      key_value |= 0x02;
   }
   else if(cnt2 < 48)
   {
      cnt2 = 50;
      key_value &= ~0x02;
   }
}



void fw_timer_cb(void *arg)
{
   timer_ms_cnt++;
   timer_1s_cnt++;
}





/*
* wifi事件
* @param[in]   event  		       :事件
* @retval      esp_err_t           :错误类型
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/10, 初始化版本\n 
*/
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
    switch (event->event_id)
    {
    case SYSTEM_EVENT_STA_START:
        ESP_LOGI(TAG1, "SYSTEM_EVENT_STA_START");
        //创建smartconfig任务
        xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
        break;
    case SYSTEM_EVENT_STA_GOT_IP:
        ESP_LOGI(TAG1, "SYSTEM_EVENT_STA_GOT_IP");
        //sta链接成功,set事件组
        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
        break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
        ESP_LOGI(TAG1, "SYSTEM_EVENT_STA_DISCONNECTED");
        //断线重连
        esp_wifi_connect();
        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
        break;
    default:
        break;
    }
    return ESP_OK;
}







/*smartconfig事件回调
* @param[in]   status  		       :事件状态
* @retval      void                 :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/10, 初始化版本\n 
*/
static void sc_callback(smartconfig_status_t status, void *pdata)
{
    switch (status)
    {
    case SC_STATUS_WAIT:                    //等待配网
        ESP_LOGI(TAG, "SC_STATUS_WAIT");
        break;
    case SC_STATUS_FIND_CHANNEL:            //扫描信道
        ESP_LOGI(TAG, "SC_STATUS_FINDING_CHANNEL");
        break;
    case SC_STATUS_GETTING_SSID_PSWD:       //获取到ssid和密码
        ESP_LOGI(TAG, "SC_STATUS_GETTING_SSID_PSWD");
        break;
    case SC_STATUS_LINK:                    //连接获取的ssid和密码
        ESP_LOGI(TAG, "SC_STATUS_LINK");
        wifi_config_t *wifi_config = pdata;
        //打印账号密码
        ESP_LOGI(TAG, "SSID:%s", wifi_config->sta.ssid);
        ESP_LOGI(TAG, "PASSWORD:%s", wifi_config->sta.password);
        //断开默认的
        ESP_ERROR_CHECK(esp_wifi_disconnect());
        //设置获取的ap和密码到寄存器
        ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_config));
        //连接获取的ssid和密码
        ESP_ERROR_CHECK(esp_wifi_connect());
        break;
    case SC_STATUS_LINK_OVER: //连接上配置后,结束
        ESP_LOGI(TAG, "SC_STATUS_LINK_OVER");
        //
        if (pdata != NULL)
        {
            uint8_t phone_ip[4] = {0};
            memcpy(phone_ip, (uint8_t *)pdata, 4);
            ESP_LOGI(TAG, "Phone ip: %d.%d.%d.%d\n", phone_ip[0], phone_ip[1], phone_ip[2], phone_ip[3]);
        }
        //发送sc结束事件
        xEventGroupSetBits(wifi_event_group, ESPTOUCH_DONE_BIT);
        break;
    default:
        break;
    }
}



/*smartconfig任务
* @param[in]   void  		       :wu
* @retval      void                 :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/10, 初始化版本\n 
*/
void smartconfig_example_task(void * parm)
{
    EventBits_t uxBits;
    //使用ESP-TOUCH配置
    ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH));
    //开始sc
    ESP_ERROR_CHECK(esp_smartconfig_start(sc_callback));
    while (1)
    {
        //死等事件组:CONNECTED_BIT | ESPTOUCH_DONE_BIT
        uxBits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
        
        //sc结束
        if (uxBits & ESPTOUCH_DONE_BIT)
        {
            ESP_LOGI(TAG, "smartconfig over");
            esp_smartconfig_stop();
            
            xTaskCreate(http_get_task, "http_get_task", 4096, NULL, 3, NULL);
            vTaskDelete(NULL);
            
        }
        //连上ap
        if (uxBits & CONNECTED_BIT)
        {
            ESP_LOGI(TAG, "WiFi Connected to ap");
        }
    }
}


/*解析json数据 只处理 解析 城市 天气 天气代码  温度  其他的自行扩展
* @param[in]   text  		       :json字符串
* @retval      void                 :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/10, 初始化版本\n 
*/
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(HTTP_TAG,"city:%s",weathe.cit);

            psub=cJSON_GetObjectItem(now,"text");
            sprintf(weathe.weather_text,"%s",psub->valuestring);
            ESP_LOGI(HTTP_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(HTTP_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);
}

/*http任务
* @param[in]   pvParameters  		:无
* @retval      void                 :无
* @note        修改日志 
*               Ver0.0.1:
                    hx-zsj, 2018/08/10, 初始化版本\n 
*/
 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;
    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(HTTP_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(HTTP_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(HTTP_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(HTTP_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);
        }
    }
}





static void user_app(void *pvParameters)
{
    static uint8_t key_value_tmp = 0;

    while(1)
    {
        if(timer_ms_cnt > 10)   //10ms
        {
            timer_ms_cnt -= 10;
            read_key();
        }

        if(key_value_tmp != key_value)
        {
            key_value_tmp = key_value;
            printf("\r\nkey_value = 0x%.2x \n",key_value);
        }

        if(timer_1s_cnt >= 1000)   //1s
        {
            timer_1s_cnt -= 1000;   

            if(led_flag)
            {
                led_flag = 0;
                gpio_set_level(LED_IO, 1);    //led亮
            }
            else
            {
                led_flag = 1;
                gpio_set_level(LED_IO, 0);    //led灭
            }      

        }

        vTaskDelay(10/ portTICK_RATE_MS);
    }
}






测试结果:
【ESP32】-【http获取天气预报】_第1张图片

你可能感兴趣的:(ESP32)