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#实现高性能Excel百万数据导出优化实战指南

《C#实现高性能Excel百万数据导出优化实战指南》在日常工作中,Excel数据导出是一个常见的需求,然而,当数据量较大时,性能和内存问题往往会成为限制导出效率的瓶颈,下面我们看看C#如何结合EPPl... 目录一、技术方案核心对比二、各方案选型建议三、性能对比数据四、核心代码实现1. MiniExcel

在React聊天应用中实现图片上传功能

《在React聊天应用中实现图片上传功能》在现代聊天应用中,除了文字和表情,图片分享也是一个重要的功能,本文将详细介绍如何在基于React的聊天应用中实现图片上传和预览功能,感兴趣的小伙伴跟着小编一起... 目录技术栈实现步骤1. 消息组件改造2. 图片预览组件3. 聊天输入组件改造功能特点使用说明注意事项

VSCode中配置node.js的实现示例

《VSCode中配置node.js的实现示例》本文主要介绍了VSCode中配置node.js的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一.node.js下载安装教程二.配置npm三.配置环境变量四.VSCode配置五.心得一.no

debian12安装docker的实现步骤

《debian12安装docker的实现步骤》本文主要介绍了debian12安装docker的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录步骤 1:更新你的系统步骤 2:安装依赖项步骤 3:添加 docker 的官方 GPG 密钥步骤

基于Redis实现附近商铺查询功能

《基于Redis实现附近商铺查询功能》:本文主要介绍基于Redis实现-附近商铺查询功能,这个功能将使用到Redis中的GEO这种数据结构来实现,需要的朋友可以参考下... 目录基于Redis实现-附近查询1.GEO相关命令2.使用GEO来实现以下功能3.使用Java实现简China编程单的附近商铺查询4.Red

使用Python实现实时金价监控并自动提醒功能

《使用Python实现实时金价监控并自动提醒功能》在日常投资中,很多朋友喜欢在一些平台买点黄金,低买高卖赚点小差价,但黄金价格实时波动频繁,总是盯着手机太累了,于是我用Python写了一个实时金价监控... 目录工具能干啥?手把手教你用1、先装好这些"食材"2、代码实现讲解1. 用户输入参数2. 设置无头浏

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I

Python实现剪贴板历史管理器

《Python实现剪贴板历史管理器》在日常工作和编程中,剪贴板是我们使用最频繁的功能之一,本文将介绍如何使用Python和PyQt5开发一个功能强大的剪贴板历史管理器,感兴趣的可以了解下... 目录一、概述:为什么需要剪贴板历史管理二、功能特性全解析2.1 核心功能2.2 增强功能三、效果展示3.1 主界面

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

springboot实现配置文件关键信息加解密

《springboot实现配置文件关键信息加解密》在项目配置文件中常常会配置如数据库连接信息,redis连接信息等,连接密码明文配置在配置文件中会很不安全,所以本文就来聊聊如何使用springboot... 目录前言方案实践1、第一种方案2、第二种方案前言在项目配置文件中常常会配置如数据库连接信息、Red