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

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import