ESP32 实现获取天气情况

2024-05-25 05:04

本文主要是介绍ESP32 实现获取天气情况,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

按照小安派AiPi-Eyes天气站思路,在ESP32 S3上实现获取天气情况。

一、在ESP32 S3实现

1、main.c

建立2个TASK

void app_main(void)
{//lvgl初始化xTaskCreate(guiTask, "guiTask", 1024 * 6, NULL, 5, NULL);//wifi初始化、socket、json处理taskcustom_init();
}

2、guiTask()

lVGL初始化


void guiTask(void *pvParameter)
{xGuiSemaphore = xSemaphoreCreateMutex();static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)static lv_disp_drv_t disp_drv;      // contains callback functionsESP_LOGI(TAG, "Turn off LCD backlight");gpio_set_direction(PIN_NUM_RD, GPIO_MODE_OUTPUT);gpio_set_level(PIN_NUM_RD, 1);backlight_ledc_init();ESP_LOGI(TAG, "Initialize Intel 8080 bus");esp_lcd_i80_bus_handle_t i80_bus = NULL;esp_lcd_i80_bus_config_t bus_config = {.clk_src = LCD_CLK_SRC_DEFAULT,.dc_gpio_num = PIN_NUM_DC,.wr_gpio_num = PIN_NUM_PCLK,.data_gpio_nums = {PIN_NUM_DATA0,PIN_NUM_DATA1,PIN_NUM_DATA2,PIN_NUM_DATA3,PIN_NUM_DATA4,PIN_NUM_DATA5,PIN_NUM_DATA6,PIN_NUM_DATA7,},.bus_width = 8,.max_transfer_bytes = LCD_V_RES * 220 * sizeof(uint16_t),.psram_trans_align = PSRAM_DATA_ALIGNMENT,.sram_trans_align = 4,};ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));esp_lcd_panel_io_handle_t io_handle = NULL;esp_lcd_panel_io_i80_config_t io_config = {.cs_gpio_num = PIN_NUM_CS,.pclk_hz = LCD_PIXEL_CLOCK_HZ,.trans_queue_depth = 10,.dc_levels = {.dc_idle_level = 0,.dc_cmd_level = 0,.dc_dummy_level = 0,.dc_data_level = 1,},.on_color_trans_done = notify_lvgl_flush_ready,.user_ctx = &disp_drv,.lcd_cmd_bits = LCD_CMD_BITS,.lcd_param_bits = LCD_PARAM_BITS,.flags.swap_color_bytes = true,};ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));esp_lcd_panel_handle_t panel_handle = NULL;ESP_LOGI(TAG, "Install LCD driver of ili9225");esp_lcd_panel_dev_config_t panel_config = {.reset_gpio_num = PIN_NUM_RST,.color_space = ESP_LCD_COLOR_SPACE_RGB,.bits_per_pixel = 16,};ESP_ERROR_CHECK(esp_lcd_new_panel_ili9225(io_handle, &panel_config, &panel_handle));esp_lcd_panel_reset(panel_handle);esp_lcd_panel_init(panel_handle);ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));ESP_LOGI(TAG, "Initialize LVGL library");lv_init();// alloc draw buffers used by LVGL// it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sizedlv_color_t *buf1 = NULL;lv_color_t *buf2 = NULL;buf1 = heap_caps_malloc(LCD_V_RES * 50 * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);buf2 = heap_caps_malloc(LCD_V_RES * 50 * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);assert(buf1);assert(buf2);ESP_LOGI(TAG, "buf1@%p, buf2@%p", buf1, buf2);// initialize LVGL draw bufferslv_disp_draw_buf_init(&disp_buf, buf1, buf2, LCD_V_RES * 50);ESP_LOGI(TAG, "Register display driver to LVGL");lv_disp_drv_init(&disp_drv);disp_drv.hor_res = LCD_H_RES;disp_drv.ver_res = LCD_V_RES;disp_drv.flush_cb = lvgl_flush_cb;disp_drv.draw_buf = &disp_buf;disp_drv.user_data = panel_handle;// lv_disp_t *disp = lv_disp_drv_register(&disp_drv);lv_disp_drv_register(&disp_drv);ESP_LOGI(TAG, "Install LVGL tick timer");// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)const esp_timer_create_args_t lvgl_tick_timer_args = {.callback = &increase_lvgl_tick,.name = "lvgl_tick"};esp_timer_handle_t lvgl_tick_timer = NULL;ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, LVGL_TICK_PERIOD_MS * 1000));ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191));// Update duty to apply the new valueESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));// First to print one framelv_timer_handler();lv_obj_t *screen = lv_obj_create(NULL);lv_obj_set_style_bg_color(screen,lv_color_hex(0x000000),LV_PART_MAIN);lv_scr_load(screen);static lv_style_t style;lv_style_init(&style);lv_style_set_bg_color(&style, lv_color_make(0xFF, 0xff, 0xff));lv_style_set_bg_opa(&style,LV_OPA_10);lv_style_set_border_color(&style, lv_color_make(0xFF, 0x00, 0xff));lv_style_set_text_color(&style,lv_color_make(0x00, 0x00, 0xff));label1=lv_label_create(lv_scr_act());lv_obj_add_style(label1, &style, 0);lv_obj_set_pos(label1, 10, 10);                                    /*Set its position*/lv_obj_set_size(label1, 160, 32);                                  /*Set its size*/lv_label_set_text(label1, "Weather");lv_obj_set_style_text_color(label1, lv_color_make(0xff, 0x00, 0x00), LV_PART_MAIN|LV_STATE_DEFAULT);//城市label_city=lv_label_create(lv_scr_act());lv_obj_set_pos(label_city, 10, 50);                                    /*Set its position*/lv_obj_set_size(label_city, 100, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_city, lv_color_make(0xff, 0xff, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);//温度label_tem=lv_label_create(lv_scr_act());lv_obj_set_pos(label_tem, 120, 50);                                    /*Set its position*/lv_obj_set_size(label_tem, 60, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_tem, lv_color_make(0xff, 0xff, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);//天气label_wea_img=lv_label_create(lv_scr_act());lv_obj_set_pos(label_wea_img, 10, 90);                                    /*Set its position*/lv_obj_set_size(label_wea_img, 160, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_wea_img, lv_color_make(0xff, 0xff, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);//湿度label_humidity=lv_label_create(lv_scr_act());lv_obj_set_pos(label_humidity, 80, 90);                                    /*Set its position*/lv_obj_set_size(label_humidity, 60, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_humidity, lv_color_make(0x00, 0xff, 0x00), LV_PART_MAIN|LV_STATE_DEFAULT);//日期label_date=lv_label_create(lv_scr_act());lv_obj_set_pos(label_date, 20, 130);                                    /*Set its position*/lv_obj_set_size(label_date, 170, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_date, lv_color_make(0x00, 0x00, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);ESP_LOGI(TAG, "LVGL interface init OK!");while (1){vTaskDelay(pdMS_TO_TICKS(1000));if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)){lv_timer_handler();xSemaphoreGive(xGuiSemaphore);}}free(buf1);free(buf2);vTaskDelete(NULL);
}

3、void custom_init(void)

建立queue处理TASK

建立定时,1个小时执行一次重新获取天气信息

执行exmple_connect(),连接WIFI

向queue模拟发送获得IP成功,触发queue下一步操作

void custom_init(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());queue = xQueueCreate(1, 1024*2);xTaskCreate(queue_task, "queue task", 1024*6, NULL, 2, NULL);http_timers = xTimerCreate("http_timers", pdMS_TO_TICKS(1000), pdTRUE, 0, http_hour_requst_time);vTaskDelay(4000 / portTICK_PERIOD_MS);static char* queue_buff;queue_buff = pvPortMalloc(128);memset(queue_buff, 0, 128);sprintf(queue_buff, "{\"ip\":{\"IP\":\"%s\"}}","11.11.11.11");//前面example_connect()不可控,运行到这里应该已经获得ip了,向QUEUE模拟发送一个ip已经获得的消息,触发执行后面的程序xQueueSend(queue, queue_buff, portMAX_DELAY);vPortFree(queue_buff);
}

 4、static void queue_task(void* arg)

根据进入QUEUE的信息,执行不同的任务,一个守护task

static int cjson__analysis_type(char* json_data)
{cJSON* root = cJSON_Parse(json_data);//ESP_LOGI(TAG, "json_data:%s",json_data);if (root==NULL) {printf("[%s] is not json\r\n", __func__);return 0;}cJSON* wifi = cJSON_GetObjectItem(root, "WiFi");if (wifi) {cJSON_Delete(root);return 1;}cJSON* ip = cJSON_GetObjectItem(root, "ip");if (ip) {cJSON_Delete(root);return 2;}cJSON* weather = cJSON_GetObjectItem(root, "weather");if (weather) {cJSON_Delete(root);return 3;}cJSON_Delete(root);return 0;
}static void queue_task(void* arg)
{char* queue_buff = NULL;queue_buff = pvPortMalloc(1024*2);while (1){vTaskDelay(pdMS_TO_TICKS(100));memset(queue_buff, 0, 1024*2);xQueueReceive(queue, queue_buff, portMAX_DELAY);switch (cjson__analysis_type(queue_buff)){case 0:printf("queue_buff:%s\r\n",queue_buff);break;case 1: //wifibreak;case 2: //ipif (https_Handle!=NULL) {vTaskDelete(https_Handle);}xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, &https_Handle);break;case 3: //weathervTaskSuspend(https_Handle);cjson_get_weather(queue_buff);break;default:break;}}vPortFree(queue_buff);
}

5、static void http_hour_requst_time(TimerHandle_t timer),

每1个小时重新执行一次获取天气信息

static void http_hour_requst_time(TimerHandle_t timer)
{if (timers_http>=60*60) {//LOG_I("Timed to http update,start https request");vTaskResume(https_Handle);timers_http = 0;}else {timers_http++;}}

6、static void http_get_task(void *pvParameters)

向网站发送API获取信息,返回天气信息入QUEUE。

#define WEB_SERVER "v1.yiketianqi.com"
#define WEB_PORT "80"
#define WEB_PATH "/api?unescape=1&version=v61&appid=替换成自己的ID&appsecret=替换成自己的KEY"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";static char* https_get_data(const char* https_request_data)
{char* request_data = https_request_data;printf("https_get_data:\r\n%s\r\n",request_data);static char* https_data;https_data = pvPortMalloc(1024*2);memset(https_data, 0, 1024*2);request_data += 2;char* date = pvPortMalloc(64);char* request_value = strtok(request_data, "\n");for (size_t i = 0; i < 13; i++){printf("[%d]%s\r\n", i,request_value);if (i==2) strcpy(date, request_value);if(i==12) strcpy(https_data, request_value);memset(request_value, 0, strlen(request_value));request_value = strtok(NULL, "\n");}vPortFree(date);return https_data;
}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;char recv_buf[64];static char* buff;char* queue_buff = NULL;buff = pvPortMalloc(2*1024);memset(buff, 0, 2*1024);while(1) {int err = getaddrinfo(WEB_SERVER, WEB_PORT, &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);strncat(buff, recv_buf, r);     //for(int i = 0; i < r; i++) {putchar(recv_buf[i]);}} while(r > 0);ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", r, errno);close(s);queue_buff = pvPortMalloc(1024*3);memset(queue_buff, 0, 1024*3);sprintf(queue_buff, "{\"weather\":%s}", https_get_data(buff));xQueueSend(queue, queue_buff, portMAX_DELAY);xTimerStart(http_timers, portMAX_DELAY);vPortFree(buff);vTaskDelay(50/portTICK_PERIOD_MS);for(int countdown = 10; countdown >= 0; countdown--) {ESP_LOGI(TAG, "%d... ", countdown);vTaskDelay(1000 / portTICK_PERIOD_MS);}ESP_LOGI(TAG, "Starting again!");}}

7、void cjson_get_weather(char* weather_data)

处理json,并在LCD显示。

void cjson_get_weather(char* weather_data)
{cJSON * item = NULL;//cjson对象cJSON* root = cJSON_Parse(weather_data );root=   cJSON_GetObjectItem(root, "weather");if (!root){printf("Error before: [%s]\n",cJSON_GetErrorPtr());}else{item = cJSON_GetObjectItem(root, "cityEn");			//城市lv_label_set_text(label_city, item->valuestring);item = cJSON_GetObjectItem(root, "tem");			//温度lv_label_set_text(label_tem, item->valuestring);item = cJSON_GetObjectItem(root, "wea_img");			//wealv_label_set_text(label_wea_img, item->valuestring);item = cJSON_GetObjectItem(root, "humidity");			//wealv_label_set_text(label_humidity, item->valuestring);item = cJSON_GetObjectItem(root, "date");lv_label_set_text(label_date, item->valuestring);}cJSON_free(item);}

二、说明

1、利用了example中的example_connect()函数实现wifi连接,需要做一下配置:

CMakeLists.txt增加:

set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)

 idf.py menuconfig 设置SSID和password

2、生成的BIN大于1M,Partition Table中选择“Single factory app(large)”,可以支持到1.5M

这篇关于ESP32 实现获取天气情况的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1000550

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

C#实现一键批量合并PDF文档

《C#实现一键批量合并PDF文档》这篇文章主要为大家详细介绍了如何使用C#实现一键批量合并PDF文档功能,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言效果展示功能实现1、添加文件2、文件分组(书签)3、定义页码范围4、自定义显示5、定义页面尺寸6、PDF批量合并7、其他方法

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Python实现精确小数计算的完全指南

《Python实现精确小数计算的完全指南》在金融计算、科学实验和工程领域,浮点数精度问题一直是开发者面临的重大挑战,本文将深入解析Python精确小数计算技术体系,感兴趣的小伙伴可以了解一下... 目录引言:小数精度问题的核心挑战一、浮点数精度问题分析1.1 浮点数精度陷阱1.2 浮点数误差来源二、基础解决

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo