基于Chappie-II的二次开发日志-3

期末和考研一堆事情,开发日志虽然很久没写了但是代码是一直有在更新的。接着上次的工作,为WiFi连接新增了保存上次WiFi的功能。
本文主要包括:

  • 使用nvs存储WiFi信息
  • 修正WIFI连接逻辑

使用NVS存储WiFi信息

参考ESP32存储配网信息+LED显示配网状态+按键清除配网信息(附源码) - 汉塘阿德 - 博客园
NVS 是 ESP32 提供的一个持久化存储机制,用于存储小量的配置和状态数据。使用 NVS 需要先进行初始化,打开存储空间,然后进行读写操作,最后提交更改并关闭存储。
因此向ChappieUI.cpp中添加代码,使得NVS能随之初始化。

    esp_err_t err = nvs_flash_init();
    
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        // 如果 NVS 空间不足或存在新版本的 NVS 数据,需要格式化 NVS
        ESP_ERROR_CHECK(nvs_flash_erase());  // 格式化 NVS
        err = nvs_flash_init();  // 再次初始化
    }

并编写读/写nvs和标志位重置的函数。
首先添加部分前置条件

//是否配置的标志位
typedef enum{
    wifi_unconfiged = 0,
    wifi_configed = 0xAA,
}wifi_info_str_t;
//esp32的wifi配置结构体
wifi_config_t wifi_config;
//其结构体中前32+64是ssid和密码
#define ID_AND_PWD_LEN (32+64)

读取

    static esp_err_t readWifiConfig(wifi_config_t *sta_config)
    {
        nvs_handle nvs;
        unsigned char u8WifiConfigVal;
        //  0.打开
        nvs_open("WIFI_CONFIG", NVS_READWRITE, &nvs); 
        //  1.读取标志位,并判断
        nvs_get_u8(nvs, "WifiConfigFlag", &u8WifiConfigVal);
        if(u8WifiConfigVal != wifi_configed){
            // 1.1 没有配过网,关闭nvs,返回错误码
            ESP_LOGE("WIFI", "no wifi config,read fail!");
            nvs_close(nvs); 
            return ESP_FAIL;
        }else{      
            //  1.2 进入下个步骤
            ESP_LOGI("WIFI", "wifi configed,read ok!");    
        }
        //  2.读取上一次配网的ID,password
        uint32_t len = ID_AND_PWD_LEN;
        esp_err_t err = nvs_get_blob(nvs, "wifi_config", sta_config, &len);

        ESP_LOGI("WIFI", "readout  SSID:%s", sta_config->sta.ssid);
        ESP_LOGI("WIFI", "readout  PASSWORD:%s", sta_config->sta.password);
        // 3.关闭nvs退出
        nvs_close(nvs);
        return err;
    }

写入

    /**
     * @brief  保存wifi配置参数结构体变量wifi_config到nvs
     * @param  wifi_config      wifi配置参数
     */
    static void saveWifiConfig(wifi_config_t *wifi_config)
    {
        nvs_handle nvs;
        //  0.打开
        nvs_open("WIFI_CONFIG", NVS_READWRITE, &nvs); 
        //  1.写入标记 0xaa,表示已经配过网
        nvs_set_u8(nvs, "WifiConfigFlag", wifi_configed);
        //  2.写入AP ID和AP password
        ESP_ERROR_CHECK(nvs_set_blob(nvs, "wifi_config", wifi_config, ID_AND_PWD_LEN));
        //  3.提交 并保存表的内容
        ESP_ERROR_CHECK(nvs_commit(nvs)); 
        //  4.关闭nvs退出
        nvs_close(nvs);                   
    }

标志位重置

    void clearWiFiConfigFlag(void){
        nvs_handle nvs;
        //  0.打开
        nvs_open("WIFI_CONFIG", NVS_READWRITE, &nvs); 
        //  1.写入标记 0x00,清除配网标记
        nvs_set_u8(nvs, "WifiConfigFlag", wifi_unconfiged);
        //  2.提交 并保存表的内容
        ESP_ERROR_CHECK(nvs_commit(nvs)); 
        //  3.关闭nvs退出
        nvs_close(nvs); 
    }

这样,当我们通过ESP-TOUCH配网以后,就能读出wifi的ssid和密码,并写入nvs,下一次启动wifi连接时,自动尝试对应的wifi能否成功连接,若不能连接则等待手动配网。

修正WIFI连接逻辑

先前编写的WiFi连接在后续的测试里不仅简陋而且各种BUG,干脆直接配合-1屏的WiFi按钮和nvs功能重新整理。
首先为WiFi、蓝牙以及时间更新添加标志位。

/* Structure to hold device status */
struct DeviceStatus_t {
    bool updated = false;
    bool autoScreenOff = false;
    bool WifiOn = false;
    bool timeupdated = false;
    bool BleOn = false;
    uint8_t brightness = 127;
    uint32_t autoScreenOffTime = 20000;
};
static DeviceStatus_t _device_status;

然后找到void App_Launcher::panel_control_pad_event_cb(lv_event_t * e)
在其中添加对应的事件响应

        /* If enable wifi */
        else if (obj == ui_ButtonWifi) {
            if (lv_obj_get_state(obj) == (LV_STATE_CHECKED | LV_STATE_FOCUSED)) {
                _device_status.WifiOn = true;
            }
            else {
                _device_status.WifiOn = false;
                WiFi.disconnect();
                ESP_LOGI("WIFI","WiFi Disconnect");
            }
        }
        /* If enable ble */
        else if (obj == ui_ButtonBle) {
            if (lv_obj_get_state(obj) == (LV_STATE_CHECKED | LV_STATE_FOCUSED)) {
                _device_status.BleOn = true;
            }
            else {
                _device_status.BleOn = false;
            }
        }

为保证UI创建时,wifi按钮能处于默认状态,并在wifi启动后,-1屏刷新的情况下wifi按钮能保持被按下的状态。
首先在void App_Launcher::onCreate()中添加代码

        if (_device_status.WifiOn) {
            lv_obj_add_state(ui_ButtonWifi, (LV_STATE_CHECKED | LV_STATE_FOCUSED));
        }
        if (_device_status.timeupdated) {
            _device_status.timeupdated = false;
        }
        if (_device_status.BleOn) {
            lv_obj_add_state(ui_ButtonBle, (LV_STATE_CHECKED | LV_STATE_FOCUSED));
        }

然后在void App_Launcher::updateDeviceStatus()中添加

        /**
         * @brief wifi按钮按下启动配网
         */
        if (_device_status.WifiOn && !_device_status.timeupdated && (WiFi.status() != WL_CONNECTED)){
            WiFi_config();
            _device_status.timeupdated = true;
            if(WiFi.status() != WL_CONNECTED){
                WiFi.disconnect();
                _device_status.WifiOn = false;
                _device_status.timeupdated = false;
            }
        }

这其中的WiFi_config()只是通过xTaskCreatePinnedToCore(task_WiFiConnect, "TaskWiFiConnect", 6*1024, NULL, 1, NULL, 0);创建task,真正的功能代码集中在static void task_WiFiConnect(void *xTask1)中,代码本身阅读性还可以,不用多做说明。

    static void task_WiFiConnect(void *xTask1){
        
        if(readWifiConfig(&wifi_config) == ESP_OK){
            wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
            //	1.已经配过网,直接连AP
            wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
            ESP_ERROR_CHECK(esp_wifi_init(&cfg));
            ESP_LOGI("WIFI","WiFi init.");
            /* 设置WiFi的工作模式为 STA */
            ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
            ESP_LOGI("WIFI","Mode: STA");
            /* 设置WiFi连接的参数,主要是ssid和password */
            ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
            ESP_LOGI("WIFI","Set config");
            /* 启动WIFI 驱动程序*/
            ESP_ERROR_CHECK(esp_wifi_start());  
            ESP_LOGI("WIFI","WiFi Start");      
            /* 启动WiFi连接到 AP*/
            //ESP_ERROR_CHECK(esp_wifi_connect());
            while(esp_wifi_connect()!=ESP_OK){ vTaskDelay(200); }
            vTaskDelay(100);
            ESP_LOGD("WIFI_CFG","SSID: %s PWD: %s",wifi_config.sta.ssid,wifi_config.sta.password);
            ESP_LOGI("WIFI","Status: Connected IP: %s",WiFi.localIP().toString().c_str());
            ESP_LOGD("WIFI","SSID: %s PWD: %s",WiFi.SSID(),WiFi.psk());
            vTaskDelete(NULL);
        }
        else{
            WiFi.mode(WIFI_STA);
            ESP_LOGI("WIFI", "WiFi mode : STA");
            ESP_LOGI("WIFI", "Try to connect");
            WiFi.begin();
            WiFi.beginSmartConfig();
            clearWiFiConfigFlag();
            //ESP_ERROR_CHECK(WiFi.begin());
            //ESP_ERROR_CHECK(WiFi.beginSmartConfig());
            ESP_LOGI("WIFI", "Waiting for SmartConfig...");
            //UI_LOG("[WiFi] Waiting for SmartConfig...\n");
            while (!WiFi.smartConfigDone()) { vTaskDelay(200); }
            ESP_LOGI("WIFI","SmartConfig received, connecting WiFi...");
            //UI_LOG("[WiFi] SmartConfig received, connecting WiFi...\n");
            while (WiFi.status() != WL_CONNECTED) { vTaskDelay(200); }
            if(WiFi.status() == WL_CONNECTED){
                memset(&wifi_config,0,sizeof(wifi_config));
                memcpy(wifi_config.sta.ssid,WiFi.SSID().c_str(),sizeof(wifi_config.sta.ssid));
                memcpy(wifi_config.sta.password,WiFi.psk().c_str(),sizeof(wifi_config.sta.password));
                ESP_LOGD("WIFI_CFG","SSID: %s PWD: %s",wifi_config.sta.ssid,wifi_config.sta.password);
                ESP_LOGD("WIFI","SSID: %s PWD: %s",WiFi.SSID(),WiFi.psk());
                saveWifiConfig(&wifi_config);
            }
            ESP_LOGI("WIFI","Status: Connected IP: %s",WiFi.localIP().toString().c_str());
            /*补上存配置的代码*/
            ESP_LOGD("WIFI","Task close.");
            //UI_LOG("[WiFi] Connected. IP: %s\n", WiFi.localIP().toString().c_str()); 
            vTaskDelete(NULL);
        }
    }

这样就实现了按下-1屏的WiFi按钮后启动WiFi连接,并且能保存最新一次WiFi信息的功能。

总结

在写文章的时候发现好像还有bug,有空了可能需要重新修正。日志中的代码并不一定是最新的,但是Github上一般是我测试过最新的代码大概也有BUG
我正在大量将原代码中的UI_LOG替换为ESP_LOG,开发和测试时能看到更多的信息。在写这篇文章的时候碰撞检测的功能已经开发的差不多了,就是界面还很丑,还在调整参数来确保检测精度,等差不多了会继续更新日志的。

posted @ 2025-01-13 17:02  K0maru  阅读(44)  评论(0)    收藏  举报