diff --git a/.gitignore b/.gitignore index d7c20fb..dbc805f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .cursorignore src/credentials.h platformio.ini +glances.conf \ No newline at end of file diff --git a/README.md b/README.md index be64adc..96240de 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ A sleek system monitoring display powered by ESP32 that shows real-time system metrics from a Glances server. Features a customizable UI with dark/light theme support using LVGL graphics library and power-saving display controls. +Forked from [iamlite/CYD-System-Monitor](https://github.com/iamlite/CYD-System-Monitor) to add compatibility for the ESP32-2432S028R and Windows hosts. + ![Unraid](Images/device.jpeg) ## Features @@ -30,72 +32,142 @@ A sleek system monitoring display powered by ESP32 that shows real-time system m - Device status monitoring & control - Remote theme control -## Requirements +## Hardware Requirements + +Tested on **ESP32-2432S028R** ("Cheap Yellow Display") + - ESP32-D0WD-V3 (revision v3.1) + - 2.8" ILI9341 TFT Display (320x240) + - Integrated touch controller + - Built-in USB-to-serial converter -- ESP32 development board -- TFT display compatible with TFT_eSPI library - - I'm using this cheap yellow display with ESP32 built in: [aliexpress](https://s.click.aliexpress.com/e/_olrdG2w) - - The settings in this project are for this display. -- Glances server running on the target system +Alternatively, it should work with any ESP32 development board a TFT display compatible with +the lvgl and TFT_eSPI libraries ## Setup -1. Clone this repository -2. Open the project in PlatformIO +### 1. Install PlatformIO +Visit [https://platformio.org/](https://platformio.org/) and install PlatformIO IDE or the +PlatformIO Core CLI. + +### 2. Install USB Drivers (if needed) +For ESP32-2432S028R on Windows: +- Download and install CH340 drivers from the manufacturer +- Verify the device appears in Device Manager after connection (should be under "Ports (COM & LPT)" + as USB-SERIAL CH340 or something similar) + +You can also test connectivity with `esptool`: + +```bash +$ pip install esptool # Install first if necessary +$ esptool read-mac +esptool v5.0.2 +Connected to ESP32 on COM3: +Chip type: ESP32-D0WD-V3 (revision v3.1) +Features: Wi-Fi, BT, Dual Core + LP Core, 240MHz, Vref calibration in eFuse, Coding Scheme None +... +``` + +### 3. Clone the repo + +```bash +$ git clone https://github.com/your-username/CYD-System-Monitor.git +$ cd CYD-System-Monitor +``` + +### 4. Configure PlatformIO + +Rename `platformio.example.ini` to `platformio.ini` and update the library path: + +```ini +# Default Arduino library locations: +# Windows: C:\Users\\Documents\Arduino\libraries +# Linux: ~/Arduino/libraries +# macOS: ~/Documents/Arduino/libraries + +lib_extra_dirs = /path/to/your/Arduino/libraries +``` + +### 5. Configure Network Credentials + +Rename `credentials.example.h` to `credentials.h` and update: - - Rename the `platformio.example.ini` file to `platformio.ini` - - Edit the `platformio.ini` file to set the correct path to your Arduino libraries +```cpp +const char* const WIFI_SSID = "your_wifi_network"; +const char* const WIFI_PASSWORD = "your_wifi_password"; +``` -3. Configure your TFT display settings: - - Modify TFT_eSPI settings according to your display's configuration - - Adjust screen resolution in config.h if needed: +### 6. Build and Upload - ```cpp +```bash +# Build the project +pio run - extern const uint16_t screenWidth = 240; - extern const uint16_t screenHeight = 320; +# Upload firmware +pio run -t upload - ``` +# Upload filesystem (web files) +pio run -t uploadfs -4. Configure your network settings in credentials.example.h: +# Monitor serial output +pio device monitor +``` - - Rename the file to `credentials.h` - - Edit the file to set your WiFi SSID and password +### 7. Configure Glances Server - ```cpp +#### Option A: Use Web Interface +1. Connect to the CYD device's IP address in your browser (you can see the IP in the serial output when the device boots) +2. Configure Glances server host and port in the settings - const char*const WIFI_SSID = "your_ssid_here"; - const char* const WIFI_PASSWORD = "your_password_here"; +#### Option B: Use CURL +```bash +curl -X POST http://[ESP32_IP]/settings \ + -H "Content-Type: application/json" \ + -d '{"glances_host": "192.168.1.50", "glances_port": 61208}' +``` - ``` +## Troubleshooting -5. Build and upload the project using PlatformIO +### Display Not Working +1. Check TFT_eSPI configuration matches your hardware +2. Verify pin connections in `User_Setup.h` +3. Enable debug mode to see initialization messages -6. Set up your Glances server configuration in the web interface: +### No Glances Data +1. Verify Glances server is running and accessible +2. Check network connectivity +3. Enable debug mode to see API call details - - Access the web interface at the device's IP address - - Configure the Glances server IP address and port - - Choose theme colors if you want to change them - - Save the configuration +Some Glances modules can be very slow on Windows, which can cause the ESP32 application to become +unresponsive while waiting on HTTP calls. You may need to disable slow modules in glances.conf, +particularly `processcount` and `sensors`. See https://github.com/nicolargo/glances/issues/3046 -### Home Assistant Integration +### USB Connection Issues +1. Install CH340 drivers on Windows +2. Check cable supports data transfer (not just power) +3. Try different USB ports +4. Verify device appears in Device Manager/system logs -The device exposes REST API endpoints for Home Assistant integration: +## Debug Mode -- GET `/api/status` - Device status and metrics -- POST `/api/command` - Control endpoints for theme switching and device restart +To print extra diagnostic messages, you can enable debug mode either by setting +`bool debug_mode = true;` in config.cpp, or at runtime with `curl`: -#### Easy Integration +```bash +$ curl -X POST http://[ESP32_IP]/settings \ + -H "Content-Type: application/json" \ + -d '{"debug_mode": true}' +``` -A complete Home Assistant configuration example is provided in [homeassistant_example.yml](homeassistant_example.yml). This includes: +## Configuration Files -- System sensors (temperature, memory, WiFi signal, uptime) -- Binary sensors for dark mode and display state -- Switches for controlling dark mode and display power -- Commands for device restart and theme reset +### Core Configuration +- `credentials.h` - WiFi network settings +- `platformio.ini` - Build configuration and library paths +- `include/config.h` - Display resolution and debug settings -Simply copy the configuration, replace `YOUR.DEVICE.IP.HERE` with your device's IP address, and add it to your Home Assistant configuration. -You should see the entities show up in home assistant after a restart. +### Hardware Configuration +- `include/User_Setup.h` - TFT_eSPI pin mappings for CYD +- Pin configuration automatically applied via build flags ## API Endpoints diff --git a/include/User_Setup.h b/include/User_Setup.h new file mode 100644 index 0000000..53f8a50 --- /dev/null +++ b/include/User_Setup.h @@ -0,0 +1,28 @@ +// User_Setup.h for ESP32-2432S028R (CYD - Cheap Yellow Display) +// This file configures TFT_eSPI for the specific CYD hardware + +#define ILI9341_DRIVER // Generic driver for common displays + +// ESP32 CYD specific pin configuration +#define TFT_MISO 12 +#define TFT_MOSI 13 +#define TFT_SCLK 14 +#define TFT_CS 15 // Chip select control pin +#define TFT_DC 2 // Data Command control pin +#define TFT_RST -1 // Reset pin (could connect to RST pin) +#define TFT_BL 21 // Backlight control pin + +#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH +#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters +#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters +#define LOAD_FONT6 // Font 6. Large 48 pixel high font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm +#define LOAD_FONT7 // Font 7. 7 segment 48 pixel high font, needs ~2438 bytes in FLASH, only characters 1234567890:. +#define LOAD_FONT8 // Font 8. Large 75 pixel high font needs ~3256 bytes in FLASH, only characters 1234567890:-. +#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts + +#define SMOOTH_FONT + +// SPI frequency for reading (5MHz maximum) +#define SPI_FREQUENCY 27000000 +#define SPI_READ_FREQUENCY 20000000 +#define SPI_TOUCH_FREQUENCY 2500000 diff --git a/include/config.h b/include/config.h index 90a97d1..b7b586f 100644 --- a/include/config.h +++ b/include/config.h @@ -11,6 +11,12 @@ extern String glances_host; extern uint16_t glances_port; #define GLANCES_UPDATE_INTERVAL 2000 +// Debug configuration +extern bool debug_mode; +#define DEBUG_PRINT(x) if(debug_mode) { Serial.print(x); } +#define DEBUG_PRINTLN(x) if(debug_mode) { Serial.println(x); } +#define DEBUG_PRINTF(format, ...) if(debug_mode) { Serial.printf(format, __VA_ARGS__); } + extern const uint16_t screenWidth; extern const uint16_t screenHeight; struct ThemeColors diff --git a/platformio.example.ini b/platformio.example.ini index 8b09235..53cb198 100644 --- a/platformio.example.ini +++ b/platformio.example.ini @@ -7,10 +7,32 @@ board = esp32dev framework = arduino monitor_speed = 115200 lib_extra_dirs = /YOUR_PATH/libraries -build_flags = -I include -I lib/** +build_flags = + -I include + -I lib/** + -D USER_SETUP_LOADED=1 + -D ILI9341_DRIVER=1 + -D TFT_MISO=12 + -D TFT_MOSI=13 + -D TFT_SCLK=14 + -D TFT_CS=15 + -D TFT_DC=2 + -D TFT_RST=-1 + -D TFT_BL=21 + -D LOAD_GLCD=1 + -D LOAD_FONT2=1 + -D LOAD_FONT4=1 + -D LOAD_FONT6=1 + -D LOAD_FONT7=1 + -D LOAD_FONT8=1 + -D LOAD_GFXFF=1 + -D SPI_FREQUENCY=27000000 + -D SPI_READ_FREQUENCY=20000000 lib_deps = bblanchon/ArduinoJson @ ^6.21.3 + lvgl/lvgl@^8.3.0 + bodmer/TFT_eSPI@^2.5.43 ESP32WebServer Preferences diff --git a/src/config.cpp b/src/config.cpp index 4f0dd6f..8f4e962 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -3,8 +3,11 @@ #include // Screen resolution -const uint16_t screenWidth = 240; -const uint16_t screenHeight = 320; +const uint16_t screenWidth = 320; +const uint16_t screenHeight = 240; + +// Debug mode - set to true for verbose logging, false for quiet operation +bool debug_mode = false; // Glances settings String glances_host; diff --git a/src/display.cpp b/src/display.cpp index c110920..5a37b30 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -1,7 +1,7 @@ #include "display.h" #include -#define TFT_BL 27 +#define TFT_BL 21 // Correct backlight pin for CYD #define TFT_BACKLIGHT_ON HIGH TFT_eSPI tft = TFT_eSPI(); @@ -15,25 +15,40 @@ void init_display() digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); tft.begin(); - tft.setRotation(3); + tft.setRotation(3); // Landscape orientation tft.initDMA(); tft.fillScreen(TFT_BLACK); - // Allocate display buffers + // Allocate display buffers - fix the width/height issue extern const uint16_t screenHeight; extern const uint16_t screenWidth; - buf1 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * screenHeight * 10, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); - buf2 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * screenHeight * 10, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); - lv_disp_draw_buf_init(&draw_buf, buf1, buf2, screenHeight * 10); + + // For landscape mode (rotation 3), actual dimensions are swapped + uint16_t buffer_width = screenWidth; // 240 + uint16_t buffer_height = screenHeight; // 320 + + // Allocate buffers with proper size calculation + size_t buffer_size = buffer_width * 10; // 10 lines buffer + buf1 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + buf2 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + + if (buf1 == NULL || buf2 == NULL) { + Serial.println("Failed to allocate display buffers!"); + return; + } + + lv_disp_draw_buf_init(&draw_buf, buf1, buf2, buffer_size); - // Initialize display driver + // Initialize display driver with correct resolution static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); - disp_drv.hor_res = screenHeight; - disp_drv.ver_res = screenWidth; + disp_drv.hor_res = screenWidth; // 240 + disp_drv.ver_res = screenHeight; // 320 disp_drv.flush_cb = my_disp_flush; disp_drv.draw_buf = &draw_buf; lv_disp_drv_register(&disp_drv); + + Serial.println("Display initialized successfully"); } void display_sleep(bool sleep) diff --git a/src/glances_api.cpp b/src/glances_api.cpp index 06e229f..38f668a 100644 --- a/src/glances_api.cpp +++ b/src/glances_api.cpp @@ -8,16 +8,26 @@ bool GlancesAPI::fetchData(const char *endpoint, StaticJsonDocument<4096> &doc) { if (WiFi.status() != WL_CONNECTED) { + Serial.println("WiFi not connected for Glances API"); + return false; + } + + if (glances_host.length() == 0) { + Serial.println("Glances host not configured"); return false; } HTTPClient http; String url = "http://" + glances_host + ":" + String(glances_port) + endpoint; + DEBUG_PRINTF("Fetching: %s\n", url.c_str()); + http.begin(url); + http.setTimeout(5000); // 5 second timeout int httpCode = http.GET(); if (httpCode != HTTP_CODE_OK) { + Serial.printf("HTTP error %d for endpoint %s\n", httpCode, endpoint); http.end(); return false; } @@ -26,16 +36,25 @@ bool GlancesAPI::fetchData(const char *endpoint, StaticJsonDocument<4096> &doc) http.end(); DeserializationError error = deserializeJson(doc, payload); - return !error; + if (error) { + Serial.printf("JSON parse error for %s: %s\n", endpoint, error.c_str()); + return false; + } + + return true; } void GlancesAPI::updateCPUData(StaticJsonDocument<4096> &doc) { - if (!fetchData("/api/4/cpu", doc)) + if (!fetchData("/api/4/cpu", doc)) { + Serial.printf("Failed to fetch CPU data"); return; + } float cpuPercent = doc["total"].as(); int cpuCount = doc["cpucore"].as(); + + DEBUG_PRINTF("CPU: %.1f%%, Cores: %d\n", cpuPercent, cpuCount); if (cpu_arc_obj.arc && cpu_arc_obj.label) { @@ -53,8 +72,15 @@ void GlancesAPI::updateCPUData(StaticJsonDocument<4096> &doc) lv_obj_set_style_text_font(labels[2], &lv_font_montserrat_16, 0); lv_obj_set_style_text_color(labels[1], lv_color_hex(0x808080), 0); lv_obj_set_style_text_color(labels[2], lv_color_white(), 0); + + DEBUG_PRINTLN("Updated CPU arc labels"); + } else { + DEBUG_PRINTLN("CPU arc labels not found"); } - set_arc_value_animated(cpu_arc_obj.arc, cpuPercent); + set_arc_value_animated(cpu_arc_obj.arc, cpuPercent, 500); + DEBUG_PRINTF("Set CPU arc to %d%%\n", (int)cpuPercent); + } else { + DEBUG_PRINTLN("CPU arc object not initialized"); } } @@ -86,12 +112,27 @@ void GlancesAPI::updateMemoryData(StaticJsonDocument<4096> &doc) void updateGlancesData() { static unsigned long lastGlancesUpdate = 0; + static bool first_run = true; + if (millis() - lastGlancesUpdate < GLANCES_UPDATE_INTERVAL) { return; } + + if (first_run) { + Serial.println("Starting Glances data updates..."); + Serial.printf("Glances Host: %s\n", glances_host.c_str()); + Serial.printf("Glances Port: %d\n", glances_port); + Serial.printf("Debug Mode: %s\n", debug_mode ? "Enabled" : "Disabled"); + first_run = false; + } + static StaticJsonDocument<4096> doc; + + DEBUG_PRINTLN("Updating CPU data..."); GlancesAPI::updateCPUData(doc); + + DEBUG_PRINTLN("Updating Memory data..."); GlancesAPI::updateMemoryData(doc); if (GlancesAPI::fetchData("/api/4/sensors", doc)) @@ -109,18 +150,48 @@ void updateGlancesData() } } + DEBUG_PRINTLN("Updating disk data..."); if (GlancesAPI::fetchData("/api/4/fs", doc)) { unsigned long long totalSize = 0; unsigned long long usedSize = 0; + int driveCount = 0; + DEBUG_PRINTLN("Processing filesystem data:"); for (JsonVariant fs : doc.as()) { const char *mnt_point = fs["mnt_point"].as(); - if (strncmp(mnt_point, "/rootfs/mnt/disk", 15) == 0) - { + const char *fs_type = fs["fs_type"].as(); + const char *options = fs["options"].as(); + + DEBUG_PRINTF(" Drive: %s, Type: %s, Options: %s\n", mnt_point, fs_type, options); + + // For Windows: Include fixed drives (C:\, D:\, etc.), exclude removable and CD-ROM + // For Linux: Include specific mount points or all non-system mounts + bool includeInArray = false; + + if (strstr(options, "fixed") != nullptr && strstr(options, "rw") != nullptr) { + // Windows fixed drives (C:\, D:\, etc.) + includeInArray = true; + } else if (strncmp(mnt_point, "/rootfs/mnt/disk", 15) == 0) { + // Linux unRAID array disks + includeInArray = true; + } else if (mnt_point[0] == '/' && + strcmp(mnt_point, "/") != 0 && + strstr(mnt_point, "/boot") == nullptr && + strstr(mnt_point, "/snap") == nullptr && + strstr(mnt_point, "/sys") == nullptr && + strstr(mnt_point, "/proc") == nullptr && + strstr(mnt_point, "/dev") == nullptr) { + // Linux regular mount points (excluding system mounts) + includeInArray = true; + } + + if (includeInArray) { totalSize += fs["size"].as(); usedSize += fs["used"].as(); + driveCount++; + DEBUG_PRINTF(" Added to array: %s\n", mnt_point); } } @@ -128,25 +199,41 @@ void updateGlancesData() { float usagePercent = (usedSize * 100.0) / totalSize; char buf[32]; - snprintf(buf, sizeof(buf), LV_SYMBOL_DRIVE " Array: %.1f%%", usagePercent); + snprintf(buf, sizeof(buf), LV_SYMBOL_DRIVE " Drives: %.1f%%", usagePercent); update_compact_label(disk_label, buf); + DEBUG_PRINTF("Updated disk array: %.1f%% (%d drives)\n", usagePercent, driveCount); + } else { + DEBUG_PRINTLN("No drives found for array display"); } } + DEBUG_PRINTLN("Updating cache data..."); if (GlancesAPI::fetchData("/api/4/fs", doc)) { + bool cacheFound = false; for (JsonVariant fs : doc.as()) { const char *mnt_point = fs["mnt_point"].as(); - if (strcmp(mnt_point, "/rootfs/mnt/cache") == 0) - { + + // Check for various cache mount points + if (strcmp(mnt_point, "/rootfs/mnt/cache") == 0 || // unRAID cache + strcmp(mnt_point, "/cache") == 0 || // Generic cache + strcmp(mnt_point, "/var/cache") == 0 || // System cache + strstr(mnt_point, "cache") != nullptr) { // Any mount containing "cache" + float usage = fs["percent"].as(); char buf[32]; snprintf(buf, sizeof(buf), LV_SYMBOL_SAVE " Cache: %.1f%%", usage); update_compact_label(cache_label, buf); + DEBUG_PRINTF("Updated cache: %.1f%% (%s)\n", usage, mnt_point); + cacheFound = true; break; } } + + if (!cacheFound) { + DEBUG_PRINTLN("No cache or suitable drive found"); + } } if (GlancesAPI::fetchData("/api/4/uptime", doc)) diff --git a/src/gui.cpp b/src/gui.cpp index 935fcc0..ccae661 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -311,12 +311,16 @@ void applyTheme(bool darkMode) void create_system_monitor_gui() { + Serial.println("Creating system monitor GUI..."); + const ThemeColors *theme = DARK_MODE ? &dark_theme : &light_theme; lv_obj_set_style_bg_color(lv_scr_act(), theme->bg_color, 0); lv_obj_t *main_cont = lv_obj_create(lv_scr_act()); - if (!main_cont) + if (!main_cont) { + Serial.println("Failed to create main container"); return; + } lv_obj_set_size(main_cont, 320, 240); lv_obj_set_style_pad_all(main_cont, 2, 0); @@ -327,12 +331,16 @@ void create_system_monitor_gui() lv_obj_clear_flag(main_cont, LV_OBJ_FLAG_SCROLLABLE); lv_obj_t *left_col = lv_obj_create(main_cont); - if (!left_col) + if (!left_col) { + Serial.println("Failed to create left column"); return; + } lv_obj_t *right_col = lv_obj_create(main_cont); - if (!right_col) + if (!right_col) { + Serial.println("Failed to create right column"); return; + } lv_obj_set_size(left_col, 158, 240); lv_obj_set_style_pad_all(left_col, 2, 0); @@ -348,39 +356,58 @@ void create_system_monitor_gui() lv_obj_set_flex_flow(right_col, LV_FLEX_FLOW_COLUMN); lv_obj_set_flex_align(right_col, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + Serial.println("Creating CPU arc..."); cpu_arc_obj = create_arc(left_col, "CPU", theme->cpu_color); - if (!cpu_arc_obj.arc || !cpu_arc_obj.label) + if (!cpu_arc_obj.arc || !cpu_arc_obj.label) { + Serial.println("Failed to create CPU arc"); return; + } + Serial.println("Creating RAM arc..."); ram_arc_obj = create_arc(right_col, "RAM", theme->ram_color); - if (!ram_arc_obj.arc || !ram_arc_obj.label) + if (!ram_arc_obj.arc || !ram_arc_obj.label) { + Serial.println("Failed to create RAM arc"); return; + } temp_label = create_compact_label(left_col, LV_SYMBOL_WARNING " Temp: -- °C", theme); - if (!temp_label) + if (!temp_label) { + Serial.println("Failed to create temp label"); return; + } load_label = create_compact_label(left_col, LV_SYMBOL_CHARGE " Load: -.-", theme); - if (!load_label) + if (!load_label) { + Serial.println("Failed to create load label"); return; + } uptime_label = create_compact_label(left_col, LV_SYMBOL_POWER " ---", theme); - if (!uptime_label) + if (!uptime_label) { + Serial.println("Failed to create uptime label"); return; + } disk_label = create_compact_label(right_col, LV_SYMBOL_DRIVE " Array: ---%", theme); - if (!disk_label) + if (!disk_label) { + Serial.println("Failed to create disk label"); return; + } cache_label = create_compact_label(right_col, LV_SYMBOL_SAVE " Cache: ---%", theme); - if (!cache_label) + if (!cache_label) { + Serial.println("Failed to create cache label"); return; + } network_label = create_compact_label(right_col, LV_SYMBOL_DOWNLOAD " --- " LV_SYMBOL_UPLOAD " ---", theme); - if (!network_label) + if (!network_label) { + Serial.println("Failed to create network label"); return; + } SettingsManager::setThemeChangeCallback(applyTheme); - applyTheme(SettingsManager::getDarkMode()); + + Serial.println("GUI creation completed successfully!"); } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a6075f4..18b3e0f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,8 +82,15 @@ void setup() void loop() { + // Handle LVGL tasks - this should be called frequently lv_timer_handler(); + + // Update Glances data at regular intervals updateGlancesData(); + + // Handle web server requests handleWebServer(); - delay(1); + + // Add a short delay to prevent watchdog issues + delay(5); } diff --git a/src/web_server.cpp b/src/web_server.cpp index 46cd2cb..6eac585 100644 --- a/src/web_server.cpp +++ b/src/web_server.cpp @@ -1,5 +1,6 @@ #include "web_server.h" #include "settings_manager.h" +#include "config.h" #include #include #include @@ -174,6 +175,7 @@ void handleGetSettings() doc["darkMode"] = SettingsManager::getDarkMode(); doc["glances_host"] = SettingsManager::getGlancesHost(); doc["glances_port"] = SettingsManager::getGlancesPort(); + doc["debug_mode"] = debug_mode; String response; serializeJson(doc, response); @@ -226,6 +228,11 @@ void handleUpdateSettings() { SettingsManager::setGlancesPort(doc["glances_port"].as()); } + if (doc.containsKey("debug_mode")) + { + debug_mode = doc["debug_mode"].as(); + Serial.printf("Debug mode %s\n", debug_mode ? "enabled" : "disabled"); + } server.send(200, "application/json", "{\"status\":\"success\"}"); } else