knxdisplay/main/Gui/WifiSetting.cpp
2026-01-25 11:56:24 +01:00

414 lines
15 KiB
C++

#include "WifiSetting.hpp"
#include "../Wifi.hpp"
#include "../Fonts.hpp"
#include "esp_lv_adapter.h"
#include "esp_log.h"
#include <cstring>
static const char* TAG = "WifiSetting";
WifiSetting& WifiSetting::instance() {
static WifiSetting instance;
return instance;
}
void WifiSetting::show() {
if (visible_) {
return;
}
ESP_LOGI(TAG, "Showing WiFi settings");
if (esp_lv_adapter_lock(-1) == ESP_OK) {
createUI();
visible_ = true;
Wifi::instance().setStatusCallback([](bool connected) {
if (esp_lv_adapter_lock(100) == ESP_OK) {
WifiSetting::instance().updateStatusDisplay();
esp_lv_adapter_unlock();
}
});
refreshNetworkList();
refreshSavedNetworks();
updateStatusDisplay();
esp_lv_adapter_unlock();
}
}
void WifiSetting::hide() {
if (!visible_) {
return;
}
ESP_LOGI(TAG, "Hiding WiFi settings");
if (esp_lv_adapter_lock(-1) == ESP_OK) {
Wifi::instance().setStatusCallback(nullptr);
if (overlay_) {
lv_obj_del(overlay_);
overlay_ = nullptr;
statusLabel_ = nullptr;
disconnectBtn_ = nullptr;
networkList_ = nullptr;
savedList_ = nullptr;
passwordDialog_ = nullptr;
passwordInput_ = nullptr;
keyboard_ = nullptr;
}
visible_ = false;
esp_lv_adapter_unlock();
}
}
bool WifiSetting::isVisible() {
return visible_;
}
void WifiSetting::createUI() {
overlay_ = lv_obj_create(lv_scr_act());
lv_obj_set_size(overlay_, LV_PCT(100), LV_PCT(100));
lv_obj_set_style_bg_color(overlay_, lv_color_hex(0x202020), 0);
lv_obj_set_style_bg_opa(overlay_, LV_OPA_COVER, 0);
lv_obj_set_style_text_font(overlay_, Fonts::bySizeIndex(0), 0);
lv_obj_set_style_pad_all(overlay_, 10, 0);
lv_obj_clear_flag(overlay_, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* header = lv_obj_create(overlay_);
lv_obj_set_size(header, LV_PCT(100), 50);
lv_obj_align(header, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_set_style_bg_color(header, lv_color_hex(0x303030), 0);
lv_obj_set_style_pad_all(header, 5, 0);
lv_obj_clear_flag(header, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* closeBtn = lv_btn_create(header);
lv_obj_set_size(closeBtn, 40, 40);
lv_obj_align(closeBtn, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_set_style_bg_color(closeBtn, lv_color_hex(0x804040), 0);
//lv_obj_add_event_cb(closeBtn, onCloseClick, LV_EVENT_CLICKED, nullptr);
lv_obj_t* closeLbl = lv_label_create(closeBtn);
lv_label_set_text(closeLbl, "X");
lv_obj_center(closeLbl);
lv_obj_t* titleLbl = lv_label_create(header);
lv_label_set_text(titleLbl, "WiFi Settings");
lv_obj_set_style_text_font(titleLbl, Fonts::bySizeIndex(0), 0);
lv_obj_align(titleLbl, LV_ALIGN_CENTER, 0, 0);
lv_obj_t* statusSection = lv_obj_create(overlay_);
lv_obj_set_size(statusSection, LV_PCT(100), 80);
lv_obj_align_to(statusSection, header, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
lv_obj_set_style_bg_color(statusSection, lv_color_hex(0x303030), 0);
lv_obj_set_style_pad_all(statusSection, 10, 0);
lv_obj_clear_flag(statusSection, LV_OBJ_FLAG_SCROLLABLE);
statusLabel_ = lv_label_create(statusSection);
lv_label_set_text(statusLabel_, "Status: Nicht verbunden");
lv_obj_align(statusLabel_, LV_ALIGN_LEFT_MID, 0, 0);
disconnectBtn_ = lv_btn_create(statusSection);
lv_obj_set_size(disconnectBtn_, 100, 40);
lv_obj_align(disconnectBtn_, LV_ALIGN_RIGHT_MID, 0, 0);
//lv_obj_add_event_cb(disconnectBtn_, onDisconnectClick, LV_EVENT_CLICKED, nullptr);
lv_obj_add_flag(disconnectBtn_, LV_OBJ_FLAG_HIDDEN);
lv_obj_t* disconnectLbl = lv_label_create(disconnectBtn_);
lv_label_set_text(disconnectLbl, "Trennen");
lv_obj_center(disconnectLbl);
lv_obj_t* availableSection = lv_obj_create(overlay_);
lv_obj_set_size(availableSection, LV_PCT(100), 280);
lv_obj_align_to(availableSection, statusSection, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
lv_obj_set_style_bg_color(availableSection, lv_color_hex(0x303030), 0);
lv_obj_set_style_pad_all(availableSection, 10, 0);
lv_obj_clear_flag(availableSection, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* availableHeader = lv_obj_create(availableSection);
lv_obj_set_size(availableHeader, LV_PCT(100), 40);
lv_obj_align(availableHeader, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_set_style_bg_opa(availableHeader, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(availableHeader, 0, 0);
lv_obj_set_style_pad_all(availableHeader, 0, 0);
lv_obj_clear_flag(availableHeader, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* availableLbl = lv_label_create(availableHeader);
lv_label_set_text(availableLbl, "Verfuegbare Netzwerke:");
lv_obj_align(availableLbl, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_t* scanBtn = lv_btn_create(availableHeader);
lv_obj_set_size(scanBtn, 100, 35);
lv_obj_align(scanBtn, LV_ALIGN_RIGHT_MID, 0, 0);
//lv_obj_add_event_cb(scanBtn, onScanClick, LV_EVENT_CLICKED, nullptr);
lv_obj_t* scanLbl = lv_label_create(scanBtn);
lv_label_set_text(scanLbl, "Scannen");
lv_obj_center(scanLbl);
networkList_ = lv_list_create(availableSection);
lv_obj_set_size(networkList_, LV_PCT(100), 220);
lv_obj_align_to(networkList_, availableHeader, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
lv_obj_set_style_bg_color(networkList_, lv_color_hex(0x252525), 0);
lv_obj_t* savedSection = lv_obj_create(overlay_);
lv_obj_set_size(savedSection, LV_PCT(100), 200);
lv_obj_align_to(savedSection, availableSection, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
lv_obj_set_style_bg_color(savedSection, lv_color_hex(0x303030), 0);
lv_obj_set_style_pad_all(savedSection, 10, 0);
lv_obj_clear_flag(savedSection, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* savedLbl = lv_label_create(savedSection);
lv_label_set_text(savedLbl, "Gespeicherte Netzwerke:");
lv_obj_align(savedLbl, LV_ALIGN_TOP_LEFT, 0, 0);
savedList_ = lv_list_create(savedSection);
lv_obj_set_size(savedList_, LV_PCT(100), 150);
lv_obj_align(savedList_, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_set_style_bg_color(savedList_, lv_color_hex(0x252525), 0);
}
void WifiSetting::refreshNetworkList() {
ESP_LOGI(TAG, "Starting network scan");
if (networkList_) {
lv_obj_clean(networkList_);
lv_obj_t* scanningLbl = lv_list_add_text(networkList_, "Scanning...");
(void)scanningLbl;
}
Wifi::instance().scan([](std::vector<wifi_ap_record_t>& networks) {
WifiSetting& settings = WifiSetting::instance();
settings.scannedNetworks_ = networks;
if (esp_lv_adapter_lock(100) == ESP_OK) {
if (settings.networkList_) {
lv_obj_clean(settings.networkList_);
for (const auto& ap : networks) {
char signalStr[64];
int bars = 0;
if (ap.rssi >= -50) bars = 4;
else if (ap.rssi >= -60) bars = 3;
else if (ap.rssi >= -70) bars = 2;
else bars = 1;
const char* barSymbols[] = {"[# ]", "[## ]", "[### ]", "[####]"};
snprintf(signalStr, sizeof(signalStr), "%s %s %ddBm",
(const char*)ap.ssid, barSymbols[bars - 1], ap.rssi);
lv_obj_t* btn = lv_list_add_btn(settings.networkList_, LV_SYMBOL_WIFI, signalStr);
//lv_obj_add_event_cb(btn, onNetworkSelect, LV_EVENT_CLICKED, nullptr);
size_t ssidLen = strlen((const char*)ap.ssid);
char* ssidCopy = (char*)lv_malloc(ssidLen + 1);
strcpy(ssidCopy, (const char*)ap.ssid);
lv_obj_set_user_data(btn, ssidCopy);
}
if (networks.empty()) {
lv_list_add_text(settings.networkList_, "Keine Netzwerke gefunden");
}
}
esp_lv_adapter_unlock();
}
});
}
void WifiSetting::refreshSavedNetworks() {
if (!savedList_) return;
lv_obj_clean(savedList_);
auto savedNetworks = Wifi::instance().getSavedNetworks();
for (const auto& ssid : savedNetworks) {
lv_obj_t* item = lv_obj_create(savedList_);
lv_obj_set_size(item, LV_PCT(100), 40);
lv_obj_set_style_bg_color(item, lv_color_hex(0x353535), 0);
lv_obj_set_style_pad_all(item, 5, 0);
lv_obj_clear_flag(item, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* nameLbl = lv_label_create(item);
lv_label_set_text(nameLbl, ssid.c_str());
lv_obj_align(nameLbl, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_t* deleteBtn = lv_btn_create(item);
lv_obj_set_size(deleteBtn, 80, 30);
lv_obj_align(deleteBtn, LV_ALIGN_RIGHT_MID, 0, 0);
lv_obj_set_style_bg_color(deleteBtn, lv_color_hex(0x804040), 0);
//lv_obj_add_event_cb(deleteBtn, onDeleteSavedClick, LV_EVENT_CLICKED, nullptr);
char* ssidCopy = (char*)lv_malloc(ssid.size() + 1);
strcpy(ssidCopy, ssid.c_str());
lv_obj_set_user_data(deleteBtn, ssidCopy);
lv_obj_t* deleteLbl = lv_label_create(deleteBtn);
lv_label_set_text(deleteLbl, "Loeschen");
lv_obj_center(deleteLbl);
}
if (savedNetworks.empty()) {
lv_list_add_text(savedList_, "Keine gespeicherten Netzwerke");
}
}
void WifiSetting::updateStatusDisplay() {
if (!statusLabel_ || !disconnectBtn_) return;
Wifi& wifi = Wifi::instance();
if (wifi.isConnected()) {
char statusText[64];
snprintf(statusText, sizeof(statusText), "Verbunden: %s", wifi.getCurrentSSID().c_str());
lv_label_set_text(statusLabel_, statusText);
lv_obj_clear_flag(disconnectBtn_, LV_OBJ_FLAG_HIDDEN);
} else {
lv_label_set_text(statusLabel_, "Status: Nicht verbunden");
lv_obj_add_flag(disconnectBtn_, LV_OBJ_FLAG_HIDDEN);
}
}
static void showPasswordDialogAsync(void* arg) {
WifiSetting::instance().createPasswordDialogUI();
}
void WifiSetting::showPasswordDialog(const char* ssid) {
selectedSSID_ = ssid;
lv_async_call(showPasswordDialogAsync, nullptr);
}
void WifiSetting::createPasswordDialogUI() {
if (passwordDialog_) return;
ESP_LOGI(TAG, "Creating password dialog for: %s", selectedSSID_.c_str());
passwordDialog_ = lv_obj_create(lv_scr_act());
lv_obj_set_size(passwordDialog_, LV_PCT(100), LV_PCT(100));
lv_obj_set_pos(passwordDialog_, 0, 0);
lv_obj_set_style_bg_color(passwordDialog_, lv_color_hex(0x303030), 0);
lv_obj_set_style_bg_opa(passwordDialog_, LV_OPA_COVER, 0);
lv_obj_set_style_pad_all(passwordDialog_, 20, 0);
lv_obj_clear_flag(passwordDialog_, LV_OBJ_FLAG_SCROLLABLE);
char title[64];
snprintf(title, sizeof(title), "Verbinden mit: %s", selectedSSID_.c_str());
lv_obj_t* titleLbl = lv_label_create(passwordDialog_);
lv_label_set_text(titleLbl, title);
lv_obj_align(titleLbl, LV_ALIGN_TOP_MID, 0, 10);
lv_obj_t* pwLabel = lv_label_create(passwordDialog_);
lv_label_set_text(pwLabel, "Passwort:");
lv_obj_align(pwLabel, LV_ALIGN_TOP_LEFT, 10, 50);
passwordInput_ = lv_textarea_create(passwordDialog_);
lv_obj_set_size(passwordInput_, LV_PCT(90), 50);
lv_obj_align(passwordInput_, LV_ALIGN_TOP_MID, 0, 80);
lv_textarea_set_password_mode(passwordInput_, true);
lv_textarea_set_one_line(passwordInput_, true);
lv_textarea_set_placeholder_text(passwordInput_, "Passwort eingeben...");
lv_obj_t* cancelBtn = lv_btn_create(passwordDialog_);
lv_obj_set_size(cancelBtn, 150, 50);
lv_obj_align(cancelBtn, LV_ALIGN_TOP_LEFT, 20, 150);
lv_obj_set_style_bg_color(cancelBtn, lv_color_hex(0x606060), 0);
//lv_obj_add_event_cb(cancelBtn, onCancelClick, LV_EVENT_CLICKED, nullptr);
lv_obj_t* cancelLbl = lv_label_create(cancelBtn);
lv_label_set_text(cancelLbl, "Abbrechen");
lv_obj_center(cancelLbl);
lv_obj_t* connectBtn = lv_btn_create(passwordDialog_);
lv_obj_set_size(connectBtn, 150, 50);
lv_obj_align(connectBtn, LV_ALIGN_TOP_RIGHT, -20, 150);
lv_obj_set_style_bg_color(connectBtn, lv_color_hex(0x408040), 0);
//lv_obj_add_event_cb(connectBtn, onConnectClick, LV_EVENT_CLICKED, nullptr);
lv_obj_t* connectLbl = lv_label_create(connectBtn);
lv_label_set_text(connectLbl, "Verbinden");
lv_obj_center(connectLbl);
keyboard_ = lv_keyboard_create(passwordDialog_);
lv_obj_set_size(keyboard_, LV_PCT(100), 300);
lv_obj_align(keyboard_, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_keyboard_set_textarea(keyboard_, passwordInput_);
//lv_obj_add_event_cb(keyboard_, onKeyboardReady, LV_EVENT_READY, nullptr);
ESP_LOGI(TAG, "Password dialog created");
}
void WifiSetting::hidePasswordDialog() {
if (passwordDialog_) {
lv_obj_del(passwordDialog_);
passwordDialog_ = nullptr;
passwordInput_ = nullptr;
keyboard_ = nullptr;
}
selectedSSID_.clear();
}
void WifiSetting::onCloseClick(lv_event_t* e) {
(void)e;
WifiSetting::instance().hide();
}
void WifiSetting::onNetworkSelect(lv_event_t* e) {
lv_obj_t* btn = (lv_obj_t*)lv_event_get_target(e);
char* ssid = (char*)lv_obj_get_user_data(btn);
if (ssid) {
ESP_LOGI(TAG, "Selected network: %s", ssid);
WifiSetting::instance().showPasswordDialog(ssid);
}
}
void WifiSetting::onScanClick(lv_event_t* e) {
(void)e;
WifiSetting::instance().refreshNetworkList();
}
void WifiSetting::onDisconnectClick(lv_event_t* e) {
(void)e;
Wifi::instance().disconnect();
WifiSetting::instance().updateStatusDisplay();
}
void WifiSetting::onConnectClick(lv_event_t* e) {
(void)e;
WifiSetting& settings = WifiSetting::instance();
if (settings.passwordInput_ && !settings.selectedSSID_.empty()) {
const char* password = lv_textarea_get_text(settings.passwordInput_);
ESP_LOGI(TAG, "Connecting to %s", settings.selectedSSID_.c_str());
Wifi::instance().connect(settings.selectedSSID_.c_str(), password);
Wifi::instance().saveNetwork(settings.selectedSSID_.c_str(), password);
settings.hidePasswordDialog();
settings.refreshSavedNetworks();
}
}
void WifiSetting::onCancelClick(lv_event_t* e) {
(void)e;
WifiSetting::instance().hidePasswordDialog();
}
void WifiSetting::onDeleteSavedClick(lv_event_t* e) {
lv_obj_t* btn = (lv_obj_t*)lv_event_get_target(e);
char* ssid = (char*)lv_obj_get_user_data(btn);
if (ssid) {
ESP_LOGI(TAG, "Deleting saved network: %s", ssid);
Wifi::instance().removeNetwork(ssid);
lv_free(ssid);
WifiSetting::instance().refreshSavedNetworks();
}
}
void WifiSetting::onKeyboardReady(lv_event_t* e) {
(void)e;
onConnectClick(nullptr);
}