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

相关文章

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

IDEA中新建/切换Git分支的实现步骤

《IDEA中新建/切换Git分支的实现步骤》本文主要介绍了IDEA中新建/切换Git分支的实现步骤,通过菜单创建新分支并选择是否切换,创建后在Git详情或右键Checkout中切换分支,感兴趣的可以了... 前提:项目已被Git托管1、点击上方栏Git->NewBrancjsh...2、输入新的分支的

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java easyExcel实现导入多sheet的Excel

《JavaeasyExcel实现导入多sheet的Excel》这篇文章主要为大家详细介绍了如何使用JavaeasyExcel实现导入多sheet的Excel,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录1.官网2.Excel样式3.代码1.官网easyExcel官网2.Excel样式3.代码

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机