From 0f7686d5a591bc326d42bc51912f38487892538c Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Tue, 30 Sep 2025 21:53:40 +0200 Subject: [PATCH] add simulation to UI Signed-off-by: Peter Siegmund --- .../components/insa/include/ui/LightMenu.h | 42 ++++++------- .../insa/src/ui/ClockScreenSaver.cpp | 26 ++++---- firmware/components/insa/src/ui/LightMenu.cpp | 14 ++--- .../components/led-manager/include/color.h | 3 + .../led-manager/src/led_strip_ws2812.c | 2 + .../include/hal_native/PersistenceManager.h | 63 ------------------- firmware/components/simulator/CMakeLists.txt | 5 +- .../components/simulator/include/simulator.h | 5 +- .../components/simulator/include/storage.h | 1 - .../src/{simulator.c => simulator.cpp} | 50 +++++++++++++-- .../simulator/src/{storage.c => storage.cpp} | 0 firmware/main/app_task.cpp | 24 +++++-- firmware/main/main.cpp | 9 +-- 13 files changed, 113 insertions(+), 131 deletions(-) delete mode 100644 firmware/components/persistence-manager/include/hal_native/PersistenceManager.h rename firmware/components/simulator/src/{simulator.c => simulator.cpp} (92%) rename firmware/components/simulator/src/{storage.c => storage.cpp} (100%) diff --git a/firmware/components/insa/include/ui/LightMenu.h b/firmware/components/insa/include/ui/LightMenu.h index e53d84b..d3af7b0 100644 --- a/firmware/components/insa/include/ui/LightMenu.h +++ b/firmware/components/insa/include/ui/LightMenu.h @@ -21,13 +21,13 @@ * for controlling various aspects of the lighting system. It allows users to * adjust brightness levels, select colors, configure lighting modes, and * manage automated lighting behaviors. - * + * * The LightMenu class extends the base Menu functionality by: * - Providing light-specific control options (brightness, color, modes) * - Implementing real-time lighting preview and feedback * - Managing lighting presets and custom configurations * - Handling immediate lighting adjustments and scheduled operations - * + * * Typical lighting control features include: * - Brightness adjustment (0-100% or similar range) * - Color selection (RGB, HSV, or predefined colors) @@ -35,57 +35,57 @@ * - Timer-based automation (on/off schedules) * - Preset management (save/load favorite configurations) * - Zone-based control (if multiple light zones are supported) - * + * * The menu provides immediate visual feedback by applying changes to the * connected lighting hardware in real-time as users navigate through options. - * + * * @note This class is marked as final and cannot be inherited from. * @note Lighting changes are typically applied immediately for instant feedback, * with the option to save configurations as presets. - * + * * @see Menu for base menu functionality * @see menu_options_t for configuration structure * @see MainMenu for navigation back to main interface */ class LightMenu final : public Menu { -public: + public: /** * @brief Constructs the light control menu with the specified configuration * @param options Pointer to menu options configuration structure - * + * * @pre options must not be nullptr and must remain valid for the menu's lifetime * @pre options->u8g2 must be initialized and ready for graphics operations * @pre All callback functions in options must be properly configured * @pre Lighting hardware must be initialized and responsive * @post LightMenu is initialized with current lighting state and ready for user interaction - * + * * @details The constructor initializes the light control menu by: * - Reading current lighting system state and parameters * - Creating appropriate menu items for available lighting features * - Setting up real-time preview capabilities * - Loading saved lighting presets and configurations * - Configuring value ranges and validation for lighting parameters - * + * * The menu automatically detects available lighting capabilities and presents * only the controls that are supported by the connected hardware. This ensures * a consistent user experience across different lighting system configurations. - * + * * @note The menu does not take ownership of the options structure and assumes * it remains valid throughout the menu's lifetime. * @note Current lighting state is preserved and can be restored if the user * exits without saving changes. - * + * * @see Menu::Menu for base class construction details */ explicit LightMenu(menu_options_t *options); -private: + private: /** * @brief Handles button press events specific to light control menu items * @param menuItem * @param button Type of button that was pressed - * + * * @details Overrides the base Menu class method to provide light control-specific * button handling logic. This method processes user interactions with * lighting control items and performs appropriate actions such as: @@ -95,28 +95,28 @@ private: * - Saving/loading lighting presets * - Toggling lighting zones on/off * - Applying lighting changes immediately to hardware - * + * * The method provides real-time feedback by immediately applying lighting * changes to the connected hardware, allowing users to see the effects of * their adjustments instantly. It also handles validation to ensure that * lighting parameters remain within safe and supported ranges. - * + * * Special handling includes: * - Smooth transitions for brightness adjustments * - Color wheel navigation for color selection * - Mode cycling for lighting patterns * - Confirmation prompts for preset operations - * + * * @note This method is called by the base Menu class when a button press * occurs on a menu item, after the base class has handled standard * navigation operations. * @note Changes are applied immediately to provide instant visual feedback, * but can be reverted if the user cancels or exits without saving. - * + * * @see Menu::onButtonPressed for the base implementation * @see ButtonType for available button types */ - void onButtonPressed(const MenuItem& menuItem, ButtonType button) override; + void onButtonPressed(const MenuItem &menuItem, ButtonType button) override; /** * @brief Pointer to menu options configuration structure @@ -124,16 +124,16 @@ private: * This pointer provides access to the display context and callback functions * needed for menu operations, screen transitions, and lighting control * communication with the hardware subsystem. - * + * * The configuration enables: * - Display context for rendering lighting control interface * - Screen management callbacks for navigation to other menus * - Hardware communication for real-time lighting control * - System callbacks for lighting state persistence - * + * * @note This pointer is not owned by the LightMenu and must remain valid * throughout the menu's lifetime. It is managed by the application framework. - * + * * @warning Must not be modified after construction as it may be shared * with other components and contains critical system callbacks. */ diff --git a/firmware/components/insa/src/ui/ClockScreenSaver.cpp b/firmware/components/insa/src/ui/ClockScreenSaver.cpp index fa63b0a..8610b38 100644 --- a/firmware/components/insa/src/ui/ClockScreenSaver.cpp +++ b/firmware/components/insa/src/ui/ClockScreenSaver.cpp @@ -1,4 +1,5 @@ #include "ui/ClockScreenSaver.h" +#include "hal_esp32/PersistenceManager.h" #include "simulator.h" #include #include @@ -37,22 +38,23 @@ void ClockScreenSaver::updateTextDimensions() void ClockScreenSaver::getCurrentTimeString(char *buffer, size_t bufferSize) const { - char *simulated_time = get_time(); - if (simulated_time != nullptr) + if (m_options && m_options->persistenceManager->GetValue("light_active", false)) { - strncpy(buffer, simulated_time, bufferSize); + char *simulated_time = get_time(); + if (simulated_time != nullptr) + { + strncpy(buffer, simulated_time, bufferSize); + return; + } } - else - { - time_t rawtime; - struct tm *timeinfo; + time_t rawtime; + struct tm *timeinfo; - time(&rawtime); - timeinfo = localtime(&rawtime); + time(&rawtime); + timeinfo = localtime(&rawtime); - // Format time as HH:MM:SS - strftime(buffer, bufferSize, "%H:%M:%S", timeinfo); - } + // Format time as HH:MM:SS + strftime(buffer, bufferSize, "%H:%M:%S", timeinfo); } void ClockScreenSaver::Update(const uint64_t dt) diff --git a/firmware/components/insa/src/ui/LightMenu.cpp b/firmware/components/insa/src/ui/LightMenu.cpp index f3c0eef..95a5df3 100644 --- a/firmware/components/insa/src/ui/LightMenu.cpp +++ b/firmware/components/insa/src/ui/LightMenu.cpp @@ -1,6 +1,7 @@ #include "ui/LightMenu.h" #include "led_strip_ws2812.h" +#include "simulator.h" /** * @namespace LightMenuItem @@ -54,19 +55,12 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto { toggle(menuItem); const auto value = getItem(menuItem.getId()).getValue() == "1"; - if (value) - { - led_strip_update(LED_STATE_DAY, rgb_t{}); - } - else - { - led_strip_update(LED_STATE_OFF, rgb_t{}); - } - if (m_options && m_options->persistenceManager) { m_options->persistenceManager->SetValue(LightMenuOptions::LIGHT_ACTIVE, value); } + + start_simulation(); } break; } @@ -83,7 +77,7 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto m_options->persistenceManager->Save(); } - led_strip_update(value == 0 ? LED_STATE_DAY : LED_STATE_NIGHT, rgb_t{}); + start_simulation(); } break; } diff --git a/firmware/components/led-manager/include/color.h b/firmware/components/led-manager/include/color.h index 85b2f99..6de1694 100644 --- a/firmware/components/led-manager/include/color.h +++ b/firmware/components/led-manager/include/color.h @@ -1,6 +1,7 @@ #pragma once #include +#include typedef struct { @@ -16,7 +17,9 @@ typedef struct uint8_t v; } hsv_t; +__BEGIN_DECLS rgb_t interpolate_color_rgb(rgb_t start, rgb_t end, float factor); rgb_t interpolate_color_hsv(rgb_t start, rgb_t end, float factor); hsv_t rgb_to_hsv(rgb_t rgb); rgb_t hsv_to_rgb(hsv_t hsv); +__END_DECLS diff --git a/firmware/components/led-manager/src/led_strip_ws2812.c b/firmware/components/led-manager/src/led_strip_ws2812.c index 76eb48e..0cb979b 100644 --- a/firmware/components/led-manager/src/led_strip_ws2812.c +++ b/firmware/components/led-manager/src/led_strip_ws2812.c @@ -88,6 +88,8 @@ esp_err_t led_strip_init(void) return ESP_FAIL; } + set_all_pixels((rgb_t){.red = 0, .green = 0, .blue = 0}); + xTaskCreate(led_strip_task, "led_strip_task", 4096, NULL, tskIDLE_PRIORITY + 1, NULL); ESP_LOGI(TAG, "LED strip initialized"); diff --git a/firmware/components/persistence-manager/include/hal_native/PersistenceManager.h b/firmware/components/persistence-manager/include/hal_native/PersistenceManager.h deleted file mode 100644 index df4f2ee..0000000 --- a/firmware/components/persistence-manager/include/hal_native/PersistenceManager.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "../IPersistenceManager.h" -#include -#include -#include - -class PersistenceManager final : public IPersistenceManager { -public: - using ValueType = std::variant< - bool, - int, - float, - double, - std::string - >; - -private: - std::unordered_map m_data; - std::string m_filename; - -public: - explicit PersistenceManager(std::string filename = "settings.dat"); - ~PersistenceManager() override; - - [[nodiscard]] bool HasKey(const std::string& key) const override; - void RemoveKey(const std::string& key) override; - void Clear() override; - [[nodiscard]] size_t GetKeyCount() const override { return m_data.size(); } - - bool Save() override; - bool Load() override; - - bool SaveToFile(const std::string& filename); - bool LoadFromFile(const std::string& filename); - -protected: - void SetValueImpl(const std::string& key, bool value) override; - void SetValueImpl(const std::string& key, int value) override; - void SetValueImpl(const std::string& key, float value) override; - void SetValueImpl(const std::string& key, double value) override; - void SetValueImpl(const std::string& key, const std::string& value) override; - - [[nodiscard]] bool GetValueImpl(const std::string& key, bool defaultValue) const override; - [[nodiscard]] int GetValueImpl(const std::string& key, int defaultValue) const override; - [[nodiscard]] float GetValueImpl(const std::string& key, float defaultValue) const override; - [[nodiscard]] double GetValueImpl(const std::string& key, double defaultValue) const override; - [[nodiscard]] std::string GetValueImpl(const std::string& key, const std::string& defaultValue) const override; - -private: - static bool WriteValueToStream(SDL_IOStream* stream, const ValueType& value) ; - static bool ReadValueFromStream(SDL_IOStream* stream, ValueType& value) ; - - enum class TypeId : uint8_t { - BOOL = 0, - INT = 1, - FLOAT = 2, - DOUBLE = 3, - STRING = 4 - }; - - static TypeId GetTypeId(const ValueType& value); -}; diff --git a/firmware/components/simulator/CMakeLists.txt b/firmware/components/simulator/CMakeLists.txt index 1a87221..de0f075 100644 --- a/firmware/components/simulator/CMakeLists.txt +++ b/firmware/components/simulator/CMakeLists.txt @@ -1,8 +1,9 @@ idf_component_register(SRCS - "src/simulator.c" - "src/storage.c" + "src/simulator.cpp" + "src/storage.cpp" INCLUDE_DIRS "include" PRIV_REQUIRES led-manager + persistence-manager spiffs ) diff --git a/firmware/components/simulator/include/simulator.h b/firmware/components/simulator/include/simulator.h index 36fa0f5..f15f057 100644 --- a/firmware/components/simulator/include/simulator.h +++ b/firmware/components/simulator/include/simulator.h @@ -9,13 +9,12 @@ typedef struct int cycle_duration_minutes; } simulation_config_t; -__BEGIN_DECLS char *get_time(void); - esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue, uint8_t white, uint8_t brightness, uint8_t saturation); void cleanup_light_items(void); void start_simulate_day(void); void start_simulate_night(void); void start_simulation_task(void); -__END_DECLS +void stop_simulation_task(void); +void start_simulation(void); diff --git a/firmware/components/simulator/include/storage.h b/firmware/components/simulator/include/storage.h index 4a1f814..642ac66 100644 --- a/firmware/components/simulator/include/storage.h +++ b/firmware/components/simulator/include/storage.h @@ -1,5 +1,4 @@ #pragma once void initialize_storage(); - void load_file(const char *filename); diff --git a/firmware/components/simulator/src/simulator.c b/firmware/components/simulator/src/simulator.cpp similarity index 92% rename from firmware/components/simulator/src/simulator.c rename to firmware/components/simulator/src/simulator.cpp index e54be60..e807e74 100644 --- a/firmware/components/simulator/src/simulator.c +++ b/firmware/components/simulator/src/simulator.cpp @@ -1,6 +1,7 @@ #include "simulator.h" #include "color.h" +#include "hal_esp32/PersistenceManager.h" #include "led_strip_ws2812.h" #include "storage.h" #include @@ -332,11 +333,7 @@ void simulate_cycle(void *args) void start_simulation_task(void) { - if (simulation_task_handle != NULL) - { - vTaskDelete(simulation_task_handle); - simulation_task_handle = NULL; - } + stop_simulation_task(); simulation_config_t *config = (simulation_config_t *)heap_caps_malloc(sizeof(simulation_config_t), MALLOC_CAP_SPIRAM); @@ -355,3 +352,46 @@ void start_simulation_task(void) heap_caps_free(config); } } + +void stop_simulation_task(void) +{ + if (simulation_task_handle != NULL) + { + vTaskDelete(simulation_task_handle); + simulation_task_handle = NULL; + } +}; + +void start_simulation(void) +{ + stop_simulation_task(); + + auto persistence = PersistenceManager(); + if (persistence.GetValue("light_active", false)) + { + + int mode = persistence.GetValue("light_mode", 0); + switch (mode) + { + case 0: // Simulation mode + start_simulation_task(); + break; + + case 1: // Day mode + start_simulate_day(); + break; + + case 2: // Night mode + start_simulate_night(); + break; + + default: + ESP_LOGW(TAG, "Unknown light mode: %d", mode); + break; + } + } + else + { + led_strip_update(LED_STATE_OFF, rgb_t{}); + } +} diff --git a/firmware/components/simulator/src/storage.c b/firmware/components/simulator/src/storage.cpp similarity index 100% rename from firmware/components/simulator/src/storage.c rename to firmware/components/simulator/src/storage.cpp diff --git a/firmware/main/app_task.cpp b/firmware/main/app_task.cpp index 3be5300..16f3476 100644 --- a/firmware/main/app_task.cpp +++ b/firmware/main/app_task.cpp @@ -3,20 +3,22 @@ #include "analytics.h" #include "button_handling.h" #include "common/InactivityTracker.h" -#include "driver/i2c.h" -#include "esp_diagnostics.h" -#include "esp_log.h" -#include "esp_timer.h" #include "hal/u8g2_esp32_hal.h" #include "hal_esp32/PersistenceManager.h" #include "i2c_checker.h" #include "led_status.h" -#include "sdkconfig.h" -#include "u8g2.h" +#include "simulator.h" #include "ui/ClockScreenSaver.h" #include "ui/ScreenSaver.h" #include "ui/SplashScreen.h" #include "wifi_manager.h" +#include +#include +#include +#include +#include +#include +#include #define PIN_RST GPIO_NUM_NC @@ -47,9 +49,13 @@ static void setup_screen(void) ESP_DIAG_EVENT(TAG, "u8g2_InitDisplay"); u8g2_InitDisplay(&u8g2); + vTaskDelay(pdMS_TO_TICKS(10)); ESP_DIAG_EVENT(TAG, "u8g2_SetPowerSave"); u8g2_SetPowerSave(&u8g2, 0); + vTaskDelay(pdMS_TO_TICKS(10)); + + u8g2_ClearDisplay(&u8g2); } void setScreen(const std::shared_ptr &screen) @@ -158,6 +164,8 @@ static void handle_button(uint8_t button) void app_task(void *args) { + esp_task_wdt_add(NULL); + if (i2c_bus_scan_and_check() != ESP_OK) { led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK, @@ -180,10 +188,14 @@ void app_task(void *args) analytics_init(); #endif + start_simulation(); + auto oldTime = esp_timer_get_time(); while (true) { + esp_task_wdt_reset(); + u8g2_ClearBuffer(&u8g2); if (m_widget != nullptr) diff --git a/firmware/main/main.cpp b/firmware/main/main.cpp index 9e8d407..265c4da 100644 --- a/firmware/main/main.cpp +++ b/firmware/main/main.cpp @@ -3,7 +3,6 @@ #include "hal_esp32/PersistenceManager.h" #include "led_status.h" #include "led_strip_ws2812.h" -#include "simulator.h" #include "wifi_manager.h" #include #include @@ -31,15 +30,9 @@ void app_main(void) led_status_init(CONFIG_STATUS_WLED_PIN); led_strip_init(); - start_simulation_task(); - xTaskCreatePinnedToCore(app_task, "app_task", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1); + xTaskCreatePinnedToCore(app_task, "app_task", 8192, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1); // xTaskCreatePinnedToCore(ble_manager_task, "ble_manager", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, // portNUM_PROCESSORS - 1); - - if (persistence.GetValue("light_active", false)) - { - led_strip_update(LED_STATE_DAY, rgb_t{}); - } } __END_DECLS