ESP32 实现获取天气情况

news2024/12/24 2:17:36

按照小安派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处理task
    custom_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 functions

    ESP_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 sized
    lv_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 buffers
    lv_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 value
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));

    // First to print one frame
     lv_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: //wifi
                break;
            case 2: //ip
                if (https_Handle!=NULL) {
                    vTaskDelete(https_Handle);
                }

                xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, &https_Handle);
                break;
            case 3: //weather
                vTaskSuspend(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");			//wea
        lv_label_set_text(label_wea_img, item->valuestring);

        item = cJSON_GetObjectItem(root, "humidity");			//wea
        lv_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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1690258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ue5 中ps使用记录贴

一、快捷键记录 放大图形 ctrlalt空格 放大图形 缩小视口 ctrl空格 ctrlD 取消选区 ctrlt缩小文字 w魔棒工具 选择魔棒的时候把容差打开的多一点 二、案例 移动文字 在相应的图层选择 移动文字 修改图片里的颜色 在通道里拷贝红色通道&#xff0c;复制红色通道粘贴给正常图…

Softing工业将亮相2024年阿赫玛展会——提供过程自动化的连接解决方案

您可于2024年6月10日至14日前往美因河畔法兰克福11.0号馆&#xff0c;Softing将在C25展位展出&#xff0c;欢迎莅临&#xff01; 作为工业应用中数据交换领域公认的专家&#xff0c;Softing工业致力于帮助各行各业的客户部署网络自动化和优化生产流程。 使用Softing产品&…

kind: Telemetry

访问日志 访问日志提供了一种从单个工作负载实例的角度监控和理解行为的方法。 Istio 能够以一组可配置的格式为服务流量生成访问日志&#xff0c; 使操作员可以完全控制日志记录的方式、内容、时间和地点。 有关更多信息&#xff0c;请参阅获取 Envoy 的访问日志。 https:/…

TAS5711带EQ和DRC支持2.1声道的20W立体声8V-26V数字输入开环D类数字功放音频放大器

前言 数字功放很难搞&#xff0c;寄存器很多&#xff0c;要配置正确才有声音&#xff0c;要想声音好&#xff0c;要好好调整。 TAS5711出道很多年了&#xff0c;现在仍然在不少功放、音箱中能看到。 TAS5711特征 音频输入/输出 从 18V 电源向 8Q 负载提供 20W 功率 宽 PVDD…

Plesk面板中如何导出的MS SQL server数据库

需要导出我的SQL Server 的数据库文件&#xff0c;由于我使用的Hostease的Windows虚拟主机产品默认带普通用户权限的Plesk面板&#xff0c;但是不知道如何在Plesk上操作导出&#xff0c;因为也是对于Hostease主机产品不是很了解&#xff0c;因此联系Hostease的咨询了Hostease技…

[论文笔记]Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

引言 今天带来思维链论文 Chain-of-Thought Prompting Elicits Reasoning in Large Language Models的笔记。 作者探索了如何通过生成一系列中间推理步骤的思维链&#xff0c;显著提升大型语言模型在进行复杂推理时的能力。 1 总体介绍 语言模型的规模扩大已被证明能够带来…

redis--告警处理设置密码连接

解决当前告警提示 告警一 backlog参数控制的是三次握手的时候server端收到client ack确认号之后的队列值&#xff0c;即全连接队列 vim /etc/sysctl.conf net.core.somaxconn 1024sysctl -p 告警二 内核参数 0、表示内核将检查是否有足够的可用内存供应用进程使用&#xff1…

第八节 条件装配案例讲解

一、条件装配的作用是什么 条件装配是 Spring 框架中一个强大的特性&#xff0c;使得开发者能够创建更加灵活和可维护的应用程序。在 Spring Boot 中&#xff0c;这个特性被大量用于自动配置&#xff0c;极大地简化了基于 Spring 的应用开发。 二、条件装配注解 <dependen…

STM32_HAL_FLASH 模拟 EEPROM

1. STM32 FLASH简介 STM32F407ZGT6 的 FLASH 容量为1024K 字节&#xff0c; STM32F40xx/41xx 的闪存模块组织如图 STM32F4 的闪存模块由主存储器、系统存储器、 OPT 区域和选项字节等 4 部分组成。 主存储器&#xff0c;该部分用来存放代码和数据常数&#xff08;如 const 类型…

macOS平台安装PostgreSQL的五种方法

macOS 平台安装 PostgreSQL 数据库主要有以下五种方法。 EDB安装工具 EDB 公司提供的图像安装工具&#xff0c;支持 macOS 以及 Windows 平台。该工具可以安装 PostgreSQL 服务器、pgAdmin&#xff08;管理开发工具&#xff09;以及 StackBuilder&#xff08;安装 PostgreSQL…

漫画|基于SprinBoot+vue的漫画网站(源码+数据库+文档)

漫画网站 目录 基于SprinBootvue的漫画网站 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大…

0基础学习Mybatis系列数据库操作框架——Mysql的Geometry数据处理之WKB方案

大纲 序列化反序列化完整TypeHandlerSQL XML完整XML Mapper测试代码代码 在《0基础学习Mybatis系列数据库操作框架——Mysql的Geometry数据处理之WKT方案》中&#xff0c;我们介绍WTK方案的优点&#xff0c;也感受到它的繁琐和缺陷。比如&#xff1a; 需要借助ST_GeomFromText…

数据意外删除?安卓手机数据恢复教程来帮你解救

手机不仅仅是一个通讯工具&#xff0c;更是我们记录生活、工作、学习等各种信息的重要载体&#xff0c;无论是拍照、录音、录像&#xff0c;还是文字记录&#xff0c;手机都能轻松完成。可有时候我们会不小心删除一些重要的数据&#xff0c;这时候我们该怎么办呢&#xff1f;别…

LeetCode/NowCoder-链表经典算法OJ练习3

孜孜不倦&#xff1a;孜孜&#xff1a;勤勉&#xff0c;不懈怠。指工作或学习勤奋不知疲倦。&#x1f493;&#x1f493;&#x1f493; 目录 说在前面 题目一&#xff1a;返回倒数第k个节点 题目二&#xff1a;链表的回文结构 题目三&#xff1a;相交链表 SUMUP结尾 说在前…

分布式锁2-Zookeeper分布式锁实战

Zookeeper分布式锁实战 使用curator操作Zookeeper进行实战&#xff1b; curator是什么&#xff1a;Apache Curator包含一套高级API框架和工具类&#xff0c;它 是Apache ZooKeeper 的Java 客户端库。 准备 pom文件引入curtor依赖和zookeeper依赖 <!--curator--> <…

微信小程序开发环境的搭建

一、注册微信小程序账号 二、安装微信开发者工具 1.下载微信开发者工具。 官网下载地址&#xff1a;https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/downloads.html 2、选择稳定版Window64下载安装 3、下载完毕后&#xff0c;点击下一步安装 三、使用微信开发者工具…

linux---信号的捕捉和处理

提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、信号 可以简单理解为信号是一个进程给另一个信号发消息&#xff0c;进程收到对应的信号就执行对应的方法&#xff0c;linux信号可以分为实时信号和非实时信号 1-31为非实时信号&#xff0c;34-64为…

安全风险 - 检测Android设备系统是否已Root

在很多app中都禁止 root 后的手机使用相关app功能&#xff0c;这种场景在金融app、银行app更为常见一些&#xff1b;当然针对 root 后的手机&#xff0c;我们也可以做出风险提示&#xff0c;告知用户当前设备已 root &#xff0c;谨防风险&#xff01; 最近在安全检测中提出了一…

远动通讯屏柜的组成及各装置的作用

远动通讯屏柜的组成及各装置的作用 远动通讯屏是基于公共电网安全而投入的远方监控遥控设备&#xff1b;主要由远动装置、通讯管理机、交换机、调制解调器、GPS对时装置、数字通道防雷器、模拟通道防雷器、插线板、空气开关、屏柜及附件等设备组成、标配尺寸2260*800*600&…