implement new light mode (off/day/night/simulation)
missing: - fully connect it to the ui - setup duration in light settings Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void analytics_init(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
void analytics_init(void);
|
||||
__END_DECLS
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void wifi_manager_init(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
void wifi_manager_init(void);
|
||||
__END_DECLS
|
||||
|
||||
@@ -30,8 +30,10 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_
|
||||
#if CONFIG_WIFI_ENABLED
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
|
||||
{
|
||||
led_behavior_t led0_behavior = {
|
||||
.mode = LED_MODE_BLINK, .color = {.r = 50, .g = 50, .b = 0}, .on_time_ms = 200, .off_time_ms = 200};
|
||||
led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK,
|
||||
.color = {.red = 50, .green = 50, .blue = 0},
|
||||
.on_time_ms = 200,
|
||||
.off_time_ms = 200};
|
||||
led_status_set_behavior(0, led0_behavior);
|
||||
|
||||
esp_wifi_connect();
|
||||
@@ -40,8 +42,10 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_
|
||||
{
|
||||
if (s_retry_num < CONFIG_WIFI_CONNECT_RETRIES)
|
||||
{
|
||||
led_behavior_t led0_behavior = {
|
||||
.mode = LED_MODE_BLINK, .color = {.r = 50, .g = 50, .b = 0}, .on_time_ms = 200, .off_time_ms = 200};
|
||||
led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK,
|
||||
.color = {.red = 50, .green = 50, .blue = 0},
|
||||
.on_time_ms = 200,
|
||||
.off_time_ms = 200};
|
||||
led_status_set_behavior(0, led0_behavior);
|
||||
|
||||
esp_wifi_connect();
|
||||
@@ -49,8 +53,10 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_
|
||||
ESP_DIAG_EVENT(TAG, "Retrying to connect to the AP");
|
||||
return;
|
||||
}
|
||||
led_behavior_t led0_behavior = {
|
||||
.mode = LED_MODE_BLINK, .color = {.r = 50, .g = 0, .b = 0}, .on_time_ms = 1000, .off_time_ms = 500};
|
||||
led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK,
|
||||
.color = {.red = 50, .green = 0, .blue = 0},
|
||||
.on_time_ms = 1000,
|
||||
.off_time_ms = 500};
|
||||
led_status_set_behavior(0, led0_behavior);
|
||||
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||
@@ -59,7 +65,7 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_
|
||||
{
|
||||
led_behavior_t led0_behavior = {
|
||||
.mode = LED_MODE_SOLID,
|
||||
.color = {.r = 0, .g = 50, .b = 0},
|
||||
.color = {.red = 0, .green = 50, .blue = 0},
|
||||
};
|
||||
led_status_set_behavior(0, led0_behavior);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,11 @@
|
||||
idf_component_register(SRCS
|
||||
src/common/ColorSettingsMenu.cpp
|
||||
src/common/InactivityTracker.cpp
|
||||
src/common/Menu.cpp
|
||||
src/common/ScrollBar.cpp
|
||||
src/common/Widget.cpp
|
||||
src/data/MenuItem.cpp
|
||||
src/ui/DayColorSettingsMenu.cpp
|
||||
src/ui/LightMenu.cpp
|
||||
src/ui/LightSettingsMenu.cpp
|
||||
src/ui/MainMenu.cpp
|
||||
src/ui/NightColorSettingsMenu.cpp
|
||||
src/ui/ClockScreenSaver.cpp
|
||||
src/ui/ScreenSaver.cpp
|
||||
src/ui/SettingsMenu.cpp
|
||||
@@ -19,4 +15,5 @@ idf_component_register(SRCS
|
||||
u8g2
|
||||
led-manager
|
||||
persistence-manager
|
||||
simulator
|
||||
)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Menu.h"
|
||||
|
||||
namespace ColorSettingsMenuOptions
|
||||
{
|
||||
constexpr auto RED = "red_";
|
||||
constexpr auto GREEN = "green_";
|
||||
constexpr auto BLUE = "blue_";
|
||||
} // namespace ColorSettingsMenuOptions
|
||||
|
||||
class ColorSettingsMenu : public Menu
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a ColorSettingsMenu with the specified options
|
||||
* @param options Pointer to menu configuration options structure
|
||||
* @details Initializes the menu with color settings options
|
||||
*/
|
||||
explicit ColorSettingsMenu(menu_options_t *options, std::string prefix);
|
||||
|
||||
void onButtonPressed(const MenuItem &menuItem, const ButtonType button) override;
|
||||
|
||||
void onExit() override;
|
||||
|
||||
private:
|
||||
std::string m_suffix;
|
||||
menu_options_t *m_options;
|
||||
};
|
||||
@@ -194,9 +194,9 @@ class Menu : public Widget
|
||||
private:
|
||||
MenuItem replaceItem(int index, const MenuItem &item);
|
||||
|
||||
void render() override;
|
||||
void Render() override;
|
||||
|
||||
void onButtonClicked(ButtonType button) override;
|
||||
void OnButtonClicked(ButtonType button) override;
|
||||
|
||||
void onPressedDown();
|
||||
|
||||
|
||||
@@ -22,20 +22,20 @@
|
||||
* that indicates the current position within a scrollable range. The thumb
|
||||
* size is proportional to the visible area relative to the total content,
|
||||
* and its position reflects the current scroll offset.
|
||||
*
|
||||
*
|
||||
* The scrollbar automatically calculates thumb dimensions and position based on
|
||||
* the provided scroll values (current, minimum, maximum). It is designed to be
|
||||
* used alongside scrollable content like menus or lists to provide visual
|
||||
* feedback about scroll state.
|
||||
*
|
||||
*
|
||||
* @note This class is marked as final and cannot be inherited from.
|
||||
*
|
||||
*
|
||||
* @see Widget
|
||||
* @see menu_options_t
|
||||
*/
|
||||
class ScrollBar final : public Widget
|
||||
{
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a ScrollBar with specified position and dimensions
|
||||
* @param options Pointer to menu options configuration structure
|
||||
@@ -43,12 +43,12 @@ public:
|
||||
* @param y Y coordinate position of the scrollbar on screen
|
||||
* @param width Width of the scrollbar in pixels
|
||||
* @param height Height of the scrollbar in pixels
|
||||
*
|
||||
*
|
||||
* @pre options must not be nullptr and must remain valid for the scrollbar's lifetime
|
||||
* @pre width and height must be greater than 0
|
||||
* @pre x and y must be valid screen coordinates
|
||||
* @post ScrollBar is initialized with the specified geometry and ready for use
|
||||
*
|
||||
*
|
||||
* @note The scrollbar does not take ownership of the options structure and
|
||||
* assumes it remains valid throughout the scrollbar's lifetime.
|
||||
*/
|
||||
@@ -59,48 +59,48 @@ public:
|
||||
* @details Overrides the base Widget render method to draw the scrollbar track
|
||||
* and thumb. The appearance is determined by the current scroll state
|
||||
* and the menu options configuration.
|
||||
*
|
||||
*
|
||||
* @pre u8g2 display context must be initialized and ready for drawing
|
||||
* @post Scrollbar's visual representation is drawn to the display buffer
|
||||
*
|
||||
*
|
||||
* @note This method is called during each frame's render cycle. The scrollbar
|
||||
* track and thumb are drawn based on the current scroll values set by refresh().
|
||||
*/
|
||||
void render() override;
|
||||
void Render() override;
|
||||
|
||||
/**
|
||||
* @brief Updates the scrollbar state with new scroll values
|
||||
* @param value Current scroll position value (must be between min and max)
|
||||
* @param max Maximum scroll value (total content size)
|
||||
* @param min Minimum scroll value (default: 0, typically the start of content)
|
||||
*
|
||||
*
|
||||
* @pre value must be between min and max (inclusive)
|
||||
* @pre max must be greater than or equal to min
|
||||
* @post Scrollbar thumb position and size are recalculated based on new values
|
||||
*
|
||||
*
|
||||
* @details This method recalculates the thumb's height and vertical position
|
||||
* based on the provided scroll range and current position. The thumb
|
||||
* height represents the proportion of visible content to total content,
|
||||
* while its position represents the current scroll offset within the range.
|
||||
*
|
||||
*
|
||||
* @note Call this method whenever the scroll state changes to keep the
|
||||
* scrollbar visualization synchronized with the actual content position.
|
||||
*/
|
||||
void refresh(size_t value, size_t max, size_t min = 0);
|
||||
|
||||
private:
|
||||
private:
|
||||
// Position and dimensions
|
||||
size_t m_x; ///< X coordinate of the scrollbar's left edge
|
||||
size_t m_y; ///< Y coordinate of the scrollbar's top edge
|
||||
size_t m_width; ///< Width of the scrollbar track in pixels
|
||||
size_t m_height; ///< Height of the scrollbar track in pixels
|
||||
size_t m_x; ///< X coordinate of the scrollbar's left edge
|
||||
size_t m_y; ///< Y coordinate of the scrollbar's top edge
|
||||
size_t m_width; ///< Width of the scrollbar track in pixels
|
||||
size_t m_height; ///< Height of the scrollbar track in pixels
|
||||
|
||||
// Scroll state values
|
||||
size_t m_value; ///< Current scroll position within the range [m_min, m_max]
|
||||
size_t m_max; ///< Maximum scroll value representing the end of content
|
||||
size_t m_min; ///< Minimum scroll value representing the start of content
|
||||
size_t m_value; ///< Current scroll position within the range [m_min, m_max]
|
||||
size_t m_max; ///< Maximum scroll value representing the end of content
|
||||
size_t m_min; ///< Minimum scroll value representing the start of content
|
||||
|
||||
// Calculated thumb properties (updated by refresh())
|
||||
size_t m_thumbHeight; ///< Calculated height of the scroll thumb in pixels
|
||||
size_t m_thumbY; ///< Calculated Y position of the scroll thumb relative to track
|
||||
size_t m_thumbHeight; ///< Calculated height of the scroll thumb in pixels
|
||||
size_t m_thumbY; ///< Calculated Y position of the scroll thumb relative to track
|
||||
};
|
||||
@@ -117,7 +117,7 @@ class Widget
|
||||
* @note Override this method in derived classes to implement time-based behavior
|
||||
* such as animations, blinking effects, or timeout handling.
|
||||
*/
|
||||
virtual void update(uint64_t dt);
|
||||
virtual void Update(uint64_t dt);
|
||||
|
||||
/**
|
||||
* @brief Renders the widget to the display
|
||||
@@ -133,7 +133,7 @@ class Widget
|
||||
* Derived classes should use the u8g2 member variable to perform
|
||||
* drawing operations.
|
||||
*/
|
||||
virtual void render();
|
||||
virtual void Render();
|
||||
|
||||
/**
|
||||
* @brief Handles button press events
|
||||
@@ -148,7 +148,7 @@ class Widget
|
||||
*
|
||||
* @see ButtonType for available button types
|
||||
*/
|
||||
virtual void onButtonClicked(ButtonType button);
|
||||
virtual void OnButtonClicked(ButtonType button);
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
||||
@@ -21,9 +21,9 @@ class ClockScreenSaver final : public Widget
|
||||
{
|
||||
public:
|
||||
explicit ClockScreenSaver(menu_options_t *options);
|
||||
void update(uint64_t dt) override;
|
||||
void render() override;
|
||||
void onButtonClicked(ButtonType button) override;
|
||||
void Update(uint64_t dt) override;
|
||||
void Render() override;
|
||||
void OnButtonClicked(ButtonType button) override;
|
||||
|
||||
private:
|
||||
static constexpr int MOVE_INTERVAL = 50; // milliseconds between movements
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/ColorSettingsMenu.h"
|
||||
|
||||
class DayColorSettingsMenu final : public ColorSettingsMenu
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a DayColorSettingsMenu with the specified options
|
||||
* @param options Pointer to menu configuration options structure
|
||||
* @details Initializes the menu with day color settings options
|
||||
*/
|
||||
explicit DayColorSettingsMenu(menu_options_t *options);
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Menu.h"
|
||||
|
||||
/**
|
||||
* @class LightSettingsMenu
|
||||
* @brief Menu for configuring light system settings including sections and LED parameters
|
||||
* @details This menu extends the base Menu class to provide specialized functionality
|
||||
* for managing light system configurations. It handles dynamic section management
|
||||
* and provides persistence for user settings.
|
||||
*/
|
||||
class LightSettingsMenu final : public Menu
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a LightSettingsMenu with the specified options
|
||||
* @param options Pointer to menu configuration options structure
|
||||
* @details Initializes the menu with section counter and default section settings
|
||||
*/
|
||||
explicit LightSettingsMenu(menu_options_t *options);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Handles button press events for light settings menu items
|
||||
* @param menuItem The menu item that received the button press
|
||||
* @param button The type of button that was pressed
|
||||
* @details Manages value switching, dynamic section list updates, and
|
||||
* persistence of section values when settings are modified
|
||||
*/
|
||||
void onButtonPressed(const MenuItem& menuItem, ButtonType button) override;
|
||||
|
||||
static std::string CreateKey(int index);
|
||||
|
||||
menu_options_t *m_options; ///< Pointer to menu configuration options
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/ColorSettingsMenu.h"
|
||||
|
||||
class NightColorSettingsMenu final : public ColorSettingsMenu
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a NightColorSettingsMenu with the specified options
|
||||
* @param options Pointer to menu configuration options structure
|
||||
* @details Initializes the menu with night color settings options
|
||||
*/
|
||||
explicit NightColorSettingsMenu(menu_options_t *options);
|
||||
};
|
||||
@@ -23,9 +23,9 @@ class ScreenSaver final : public Widget
|
||||
{
|
||||
public:
|
||||
explicit ScreenSaver(menu_options_t *options);
|
||||
void update(uint64_t dt) override;
|
||||
void render() override;
|
||||
void onButtonClicked(ButtonType button) override;
|
||||
void Update(uint64_t dt) override;
|
||||
void Render() override;
|
||||
void OnButtonClicked(ButtonType button) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
||||
@@ -21,71 +21,71 @@
|
||||
* displayed when the application starts. It serves multiple purposes including
|
||||
* brand presentation, system initialization feedback, and smooth transition
|
||||
* preparation to the main application interface.
|
||||
*
|
||||
*
|
||||
* The SplashScreen class provides:
|
||||
* - Brand identity display (logos, company information, product name)
|
||||
* - System initialization progress indication
|
||||
* - Smooth animations and visual effects for professional appearance
|
||||
* - Automatic transition timing to main menu after initialization
|
||||
* - Error indication if initialization fails
|
||||
*
|
||||
*
|
||||
* Key features include:
|
||||
* - Time-based automatic progression to main menu
|
||||
* - Animated elements (fade-in effects, progress indicators)
|
||||
* - Version information display
|
||||
* - Loading status messages
|
||||
* - Graceful handling of initialization delays
|
||||
*
|
||||
*
|
||||
* The splash screen typically displays for a minimum duration to ensure users
|
||||
* can read branding information, even if system initialization completes quickly.
|
||||
* It automatically transitions to the main menu once both the minimum display
|
||||
* time and system initialization are complete.
|
||||
*
|
||||
*
|
||||
* @note This class is marked as final and cannot be inherited from.
|
||||
* @note The splash screen does not handle user input - it operates on timing
|
||||
* and system state rather than user interaction.
|
||||
*
|
||||
*
|
||||
* @see Widget for base widget functionality
|
||||
* @see menu_options_t for configuration structure
|
||||
* @see MainMenu for the target transition screen
|
||||
*/
|
||||
class SplashScreen final : public Widget
|
||||
{
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs the splash screen with specified configuration
|
||||
* @param options Pointer to menu options configuration structure
|
||||
*
|
||||
*
|
||||
* @pre options must not be nullptr and must remain valid for the splash screen's lifetime
|
||||
* @pre options->u8g2 must be initialized and ready for graphics operations
|
||||
* @pre Screen transition callbacks in options must be properly configured
|
||||
* @post SplashScreen is initialized and ready to display startup sequence
|
||||
*
|
||||
*
|
||||
* @details The constructor initializes the splash screen by:
|
||||
* - Setting up the initial display state and animations
|
||||
* - Preparing branding elements (logos, text, version info)
|
||||
* - Initializing timing controls for minimum display duration
|
||||
* - Configuring transition parameters for smooth progression
|
||||
* - Loading any required graphics resources or assets
|
||||
*
|
||||
*
|
||||
* The splash screen prepares all visual elements during construction to
|
||||
* ensure smooth rendering performance during the critical startup phase.
|
||||
* It also establishes the timing framework for controlling display duration
|
||||
* and transition timing.
|
||||
*
|
||||
*
|
||||
* @note The splash screen does not take ownership of the options structure
|
||||
* and assumes it remains valid throughout the screen's lifetime.
|
||||
* @note Graphics resources are loaded during construction, so any required
|
||||
* assets must be available at initialization time.
|
||||
*
|
||||
*
|
||||
* @see Widget::Widget for base class construction details
|
||||
*/
|
||||
explicit SplashScreen(menu_options_t *options);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Updates the splash screen state, animations, and timing logic
|
||||
* @param dt Delta time in milliseconds since the last update call
|
||||
*
|
||||
*
|
||||
* @details Overrides the base Widget update method to handle splash screen-specific
|
||||
* logic including:
|
||||
* - Animation progression (fade effects, transitions, progress indicators)
|
||||
@@ -93,31 +93,31 @@ public:
|
||||
* - System initialization status monitoring
|
||||
* - Automatic transition preparation to main menu
|
||||
* - Loading progress updates and status message changes
|
||||
*
|
||||
*
|
||||
* The update method manages the splash screen's lifecycle by tracking
|
||||
* elapsed time and system readiness state. It ensures the splash screen
|
||||
* remains visible for a minimum duration while also monitoring system
|
||||
* initialization completion. Once both conditions are met, it initiates
|
||||
* the transition to the main application interface.
|
||||
*
|
||||
*
|
||||
* Animation updates include:
|
||||
* - Fade-in effects for branding elements
|
||||
* - Progress bar or spinner animations
|
||||
* - Text transitions for status messages
|
||||
* - Smooth preparation for screen transition
|
||||
*
|
||||
*
|
||||
* @note This method is called every frame during the splash screen display
|
||||
* and must be efficient to maintain smooth visual presentation.
|
||||
* @note The method automatically handles transition to the main menu when
|
||||
* appropriate, using the callback functions provided in m_options.
|
||||
*
|
||||
*
|
||||
* @see Widget::update for the base update interface
|
||||
*/
|
||||
void update(uint64_t dt) override;
|
||||
|
||||
void Update(uint64_t dt) override;
|
||||
|
||||
/**
|
||||
* @brief Renders the splash screen visual elements to the display
|
||||
*
|
||||
*
|
||||
* @details Overrides the base Widget render method to draw all splash screen
|
||||
* elements including branding, status information, and visual effects.
|
||||
* The rendering includes:
|
||||
@@ -126,50 +126,50 @@ public:
|
||||
* - Loading progress indicators (progress bars, spinners, etc.)
|
||||
* - Status messages indicating initialization progress
|
||||
* - Background graphics and visual effects
|
||||
*
|
||||
*
|
||||
* The render method creates a professional, polished appearance that
|
||||
* reinforces brand identity while providing useful feedback about the
|
||||
* application startup process. All elements are positioned and styled
|
||||
* to create a cohesive, attractive presentation.
|
||||
*
|
||||
*
|
||||
* Rendering features include:
|
||||
* - Centered layout with balanced visual hierarchy
|
||||
* - Smooth animations and transitions
|
||||
* - Consistent typography and color scheme
|
||||
* - Progress feedback elements
|
||||
* - Error indication if initialization problems occur
|
||||
*
|
||||
*
|
||||
* @pre u8g2 display context must be initialized and ready for drawing
|
||||
* @post All splash screen visual elements are drawn to the display buffer
|
||||
*
|
||||
*
|
||||
* @note This method is called every frame and must be efficient to maintain
|
||||
* smooth visual presentation during the startup sequence.
|
||||
* @note The visual design should be consistent with the overall application
|
||||
* theme and branding guidelines.
|
||||
*
|
||||
*
|
||||
* @see Widget::render for the base render interface
|
||||
*/
|
||||
void render() override;
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* @brief Pointer to menu options configuration structure
|
||||
* @details Stores a reference to the menu configuration passed during construction.
|
||||
* This provides access to the display context for rendering operations
|
||||
* and screen transition callbacks for automatic progression to the main menu.
|
||||
*
|
||||
*
|
||||
* The configuration enables:
|
||||
* - Display context (u8g2) for graphics rendering operations
|
||||
* - Screen transition callbacks for automatic progression to main menu
|
||||
* - System integration for initialization status monitoring
|
||||
*
|
||||
*
|
||||
* The splash screen uses the setScreen callback to automatically transition
|
||||
* to the main menu once the startup sequence is complete. This ensures a
|
||||
* seamless user experience from application launch to main interface.
|
||||
*
|
||||
*
|
||||
* @note This pointer is not owned by the SplashScreen and must remain valid
|
||||
* throughout the screen's lifetime. It is managed by the application framework.
|
||||
*
|
||||
*
|
||||
* @warning Must not be modified after construction as it contains critical
|
||||
* system callbacks required for proper application flow.
|
||||
*/
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#include "common/ColorSettingsMenu.h"
|
||||
|
||||
#include "led_manager.h"
|
||||
|
||||
namespace ColorSettingsMenuItem
|
||||
{
|
||||
constexpr auto RED = 0;
|
||||
constexpr auto GREEN = 1;
|
||||
constexpr auto BLUE = 2;
|
||||
} // namespace ColorSettingsMenuItem
|
||||
|
||||
ColorSettingsMenu::ColorSettingsMenu(menu_options_t *options, std::string suffix)
|
||||
: Menu(options), m_suffix(std::move(suffix)), m_options(options)
|
||||
{
|
||||
|
||||
std::vector<std::string> values;
|
||||
for (size_t i = 0; i <= 254; i++)
|
||||
{
|
||||
values.emplace_back(std::to_string(i));
|
||||
}
|
||||
|
||||
int red_value = 0;
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
std::string key = ColorSettingsMenuOptions::RED + m_suffix;
|
||||
red_value = m_options->persistenceManager->GetValue(key, red_value);
|
||||
}
|
||||
addSelection(ColorSettingsMenuItem::RED, "Rot", values, red_value);
|
||||
|
||||
int green_value = 0;
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
std::string key = ColorSettingsMenuOptions::GREEN + m_suffix;
|
||||
green_value = m_options->persistenceManager->GetValue(key, green_value);
|
||||
}
|
||||
addSelection(ColorSettingsMenuItem::GREEN, "Gruen", values, green_value);
|
||||
|
||||
int blue_value = 0;
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
std::string key = ColorSettingsMenuOptions::BLUE + m_suffix;
|
||||
blue_value = m_options->persistenceManager->GetValue(key, blue_value);
|
||||
}
|
||||
addSelection(ColorSettingsMenuItem::BLUE, "Blau", values, blue_value);
|
||||
}
|
||||
|
||||
void ColorSettingsMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button)
|
||||
{
|
||||
switch (menuItem.getId())
|
||||
{
|
||||
case ColorSettingsMenuItem::RED:
|
||||
if (button == ButtonType::LEFT || button == ButtonType::RIGHT)
|
||||
{
|
||||
const auto item = switchValue(menuItem, button);
|
||||
const auto value = getItem(item.getId()).getIndex();
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
std::string key = ColorSettingsMenuOptions::RED + m_suffix;
|
||||
m_options->persistenceManager->SetValue(key, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ColorSettingsMenuItem::GREEN:
|
||||
if (button == ButtonType::LEFT || button == ButtonType::RIGHT)
|
||||
{
|
||||
const auto item = switchValue(menuItem, button);
|
||||
const auto value = getItem(item.getId()).getIndex();
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
std::string key = ColorSettingsMenuOptions::GREEN + m_suffix;
|
||||
m_options->persistenceManager->SetValue(key, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ColorSettingsMenuItem::BLUE:
|
||||
if (button == ButtonType::LEFT || button == ButtonType::RIGHT)
|
||||
{
|
||||
const auto item = switchValue(menuItem, button);
|
||||
const auto value = getItem(item.getId()).getIndex();
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
std::string key = ColorSettingsMenuOptions::BLUE + m_suffix;
|
||||
m_options->persistenceManager->SetValue(key, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ColorSettingsMenu::onExit()
|
||||
{
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
m_options->persistenceManager->Save();
|
||||
|
||||
led_event_data_t payload = {.value = 42};
|
||||
send_event(EVENT_LED_REFRESH, &payload);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ constexpr int BOTTOM_OFFSET = 10;
|
||||
Menu::Menu(menu_options_t *options) : Widget(options->u8g2), m_options(options)
|
||||
{
|
||||
// Set up button callback using lambda to forward to member function
|
||||
m_options->onButtonClicked = [this](const ButtonType button) { onButtonClicked(button); };
|
||||
m_options->onButtonClicked = [this](const ButtonType button) { OnButtonClicked(button); };
|
||||
}
|
||||
|
||||
Menu::~Menu()
|
||||
@@ -126,7 +126,7 @@ MenuItem Menu::replaceItem(const int index, const MenuItem &item)
|
||||
return item;
|
||||
}
|
||||
|
||||
void Menu::render()
|
||||
void Menu::Render()
|
||||
{
|
||||
// Initialize selection if not set
|
||||
if (m_selected_item >= m_items.size() && !m_items.empty())
|
||||
@@ -232,7 +232,7 @@ void Menu::renderWidget(const MenuItem *item, const uint8_t *font, const int x,
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::onButtonClicked(const ButtonType button)
|
||||
void Menu::OnButtonClicked(const ButtonType button)
|
||||
{
|
||||
// Map button input to navigation functions
|
||||
switch (button)
|
||||
@@ -362,7 +362,7 @@ void Menu::drawScrollBar() const
|
||||
// Create scrollbar instance
|
||||
ScrollBar scrollBar(m_options, u8g2->width - UIConstants::SCROLLBAR_WIDTH, 3, 1, u8g2->height - 6);
|
||||
scrollBar.refresh(m_selected_item, m_items.size());
|
||||
scrollBar.render();
|
||||
scrollBar.Render();
|
||||
}
|
||||
|
||||
void Menu::drawSelectionBox() const
|
||||
|
||||
@@ -7,7 +7,7 @@ ScrollBar::ScrollBar(const menu_options_t *options, const size_t x, const size_t
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollBar::render()
|
||||
void ScrollBar::Render()
|
||||
{
|
||||
if (m_max <= 1)
|
||||
{
|
||||
|
||||
@@ -20,14 +20,14 @@ void Widget::onExit()
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::update(uint64_t dt)
|
||||
void Widget::Update(uint64_t dt)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::render()
|
||||
void Widget::Render()
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::onButtonClicked(ButtonType button)
|
||||
void Widget::OnButtonClicked(ButtonType button)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ui/ClockScreenSaver.h"
|
||||
#include "simulator.h"
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
@@ -36,17 +37,25 @@ void ClockScreenSaver::updateTextDimensions()
|
||||
|
||||
void ClockScreenSaver::getCurrentTimeString(char *buffer, size_t bufferSize) const
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
char *simulated_time = get_time();
|
||||
if (simulated_time != nullptr)
|
||||
{
|
||||
strncpy(buffer, simulated_time, bufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
void ClockScreenSaver::Update(const uint64_t dt)
|
||||
{
|
||||
m_moveTimer += dt;
|
||||
|
||||
@@ -94,7 +103,7 @@ void ClockScreenSaver::checkBoundaryCollision()
|
||||
}
|
||||
}
|
||||
|
||||
void ClockScreenSaver::render()
|
||||
void ClockScreenSaver::Render()
|
||||
{
|
||||
// Clear screen with a black background
|
||||
u8g2_SetDrawColor(u8g2, 0);
|
||||
@@ -112,7 +121,7 @@ void ClockScreenSaver::render()
|
||||
u8g2_DrawStr(u8g2, m_posX, m_posY, timeBuffer);
|
||||
}
|
||||
|
||||
void ClockScreenSaver::onButtonClicked(ButtonType button)
|
||||
void ClockScreenSaver::OnButtonClicked(ButtonType button)
|
||||
{
|
||||
// Exit screensaver on any button press
|
||||
if (m_options && m_options->popScreen)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#include "ui/DayColorSettingsMenu.h"
|
||||
|
||||
DayColorSettingsMenu::DayColorSettingsMenu(menu_options_t *options) : ColorSettingsMenu(options, "day")
|
||||
{
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "ui/LightMenu.h"
|
||||
|
||||
#include "led_manager.h"
|
||||
#include "ui/LightSettingsMenu.h"
|
||||
#include "led_strip_ws2812.h"
|
||||
|
||||
/**
|
||||
* @namespace LightMenuItem
|
||||
@@ -9,9 +8,8 @@
|
||||
*/
|
||||
namespace LightMenuItem
|
||||
{
|
||||
constexpr auto ACTIVATE = 0; ///< ID for the light activation toggle
|
||||
constexpr auto MODE = 1; ///< ID for the light mode selection
|
||||
constexpr auto LED_SETTINGS = 2; ///< ID for the LED settings menu item
|
||||
constexpr auto ACTIVATE = 0; ///< ID for the light activation toggle
|
||||
constexpr auto MODE = 1; ///< ID for the light mode selection
|
||||
} // namespace LightMenuItem
|
||||
|
||||
namespace LightMenuOptions
|
||||
@@ -30,19 +28,17 @@ LightMenu::LightMenu(menu_options_t *options) : Menu(options), m_options(options
|
||||
}
|
||||
addToggle(LightMenuItem::ACTIVATE, "Einschalten", active);
|
||||
|
||||
// Create mode selection options (Day/Night modes)
|
||||
std::vector<std::string> values;
|
||||
values.emplace_back("Tag"); // Day mode
|
||||
values.emplace_back("Nacht"); // Night mode
|
||||
// Create mode selection options (Simulation/Day/Night modes)
|
||||
std::vector<std::string> items;
|
||||
items.emplace_back("Simulation"); // Simulation mode
|
||||
items.emplace_back("Tag"); // Day mode
|
||||
items.emplace_back("Nacht"); // Night mode
|
||||
int mode_value = 0;
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
mode_value = m_options->persistenceManager->GetValue(LightMenuOptions::LIGHT_MODE, mode_value);
|
||||
}
|
||||
addSelection(LightMenuItem::MODE, "Modus", values, mode_value);
|
||||
|
||||
// Add menu item for accessing LED settings submenu
|
||||
addText(LightMenuItem::LED_SETTINGS, "Einstellungen");
|
||||
addSelection(LightMenuItem::MODE, "Modus", items, mode_value);
|
||||
}
|
||||
|
||||
void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button)
|
||||
@@ -58,14 +54,13 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
|
||||
{
|
||||
toggle(menuItem);
|
||||
const auto value = getItem(menuItem.getId()).getValue() == "1";
|
||||
led_event_data_t payload = {.value = 42};
|
||||
if (value)
|
||||
{
|
||||
send_event(EVENT_LED_ON, &payload);
|
||||
led_strip_update(LED_STATE_DAY, rgb_t{});
|
||||
}
|
||||
else
|
||||
{
|
||||
send_event(EVENT_LED_OFF, &payload);
|
||||
led_strip_update(LED_STATE_OFF, rgb_t{});
|
||||
}
|
||||
|
||||
if (m_options && m_options->persistenceManager)
|
||||
@@ -88,17 +83,7 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
|
||||
m_options->persistenceManager->Save();
|
||||
}
|
||||
|
||||
led_event_data_t payload = {.value = value};
|
||||
send_event(EVENT_LED_DAY + value, &payload);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LightMenuItem::LED_SETTINGS: {
|
||||
// Open the LED settings submenu when SELECT is pressed
|
||||
if (button == ButtonType::SELECT)
|
||||
{
|
||||
widget = std::make_shared<LightSettingsMenu>(m_options);
|
||||
led_strip_update(value == 0 ? LED_STATE_DAY : LED_STATE_NIGHT, rgb_t{});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -113,4 +98,4 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
|
||||
{
|
||||
m_options->pushScreen(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
#include "ui/LightSettingsMenu.h"
|
||||
|
||||
#include "common/Common.h"
|
||||
#include "ui/DayColorSettingsMenu.h"
|
||||
#include "ui/NightColorSettingsMenu.h"
|
||||
|
||||
/**
|
||||
* @namespace LightSettingsMenuItem
|
||||
* @brief Constants for light settings menu item identifiers
|
||||
*/
|
||||
namespace LightSettingsMenuItem
|
||||
{
|
||||
constexpr uint8_t RGB_SETTING_DAY = 0;
|
||||
constexpr uint8_t RGB_SETTING_NIGHT = 1;
|
||||
constexpr uint8_t SECTION_COUNTER = 2;
|
||||
} // namespace LightSettingsMenuItem
|
||||
|
||||
std::string LightSettingsMenu::CreateKey(const int index)
|
||||
{
|
||||
constexpr int key_length = 20;
|
||||
char key[key_length] = "";
|
||||
snprintf(key, key_length, "section_%d", index);
|
||||
return key;
|
||||
}
|
||||
|
||||
LightSettingsMenu::LightSettingsMenu(menu_options_t *options) : Menu(options), m_options(options)
|
||||
{
|
||||
addText(LightSettingsMenuItem::RGB_SETTING_DAY, "Tag (Farbe)");
|
||||
addText(LightSettingsMenuItem::RGB_SETTING_NIGHT, "Nacht (Farbe)");
|
||||
|
||||
/*
|
||||
// Create values vector for section counts (1-99)
|
||||
std::vector<std::string> values;
|
||||
for (size_t i = 1; i <= 99; i++)
|
||||
{
|
||||
values.emplace_back(std::to_string(i));
|
||||
}
|
||||
|
||||
// Add section counter selection (allows choosing number of sections)
|
||||
auto value = 7;
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
value = m_options->persistenceManager->GetValue(CreateKey(0), value);
|
||||
}
|
||||
addSelection(LightSettingsMenuItem::SECTION_COUNTER, "Sektionen", values, value);
|
||||
|
||||
setItemSize(std::stoull(getItem(LightSettingsMenuItem::SECTION_COUNTER).getValue()),
|
||||
LightSettingsMenuItem::SECTION_COUNTER);
|
||||
*/
|
||||
}
|
||||
|
||||
void LightSettingsMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button)
|
||||
{
|
||||
std::shared_ptr<Widget> widget;
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case ButtonType::SELECT:
|
||||
switch (menuItem.getId())
|
||||
{
|
||||
case LightSettingsMenuItem::RGB_SETTING_DAY:
|
||||
widget = std::make_shared<DayColorSettingsMenu>(m_options);
|
||||
break;
|
||||
|
||||
case LightSettingsMenuItem::RGB_SETTING_NIGHT:
|
||||
widget = std::make_shared<NightColorSettingsMenu>(m_options);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_options && m_options->pushScreen)
|
||||
{
|
||||
m_options->pushScreen(widget);
|
||||
}
|
||||
break;
|
||||
|
||||
case ButtonType::RIGHT:
|
||||
case ButtonType::LEFT:
|
||||
// Handle value switching for the current menu item
|
||||
switchValue(menuItem, button);
|
||||
|
||||
// Update the section list size based on the section counter value
|
||||
if (menuItem.getId() == LightSettingsMenuItem::SECTION_COUNTER)
|
||||
{
|
||||
setItemSize(std::stoull(getItem(LightSettingsMenuItem::SECTION_COUNTER).getValue()),
|
||||
LightSettingsMenuItem::SECTION_COUNTER);
|
||||
}
|
||||
|
||||
// Persist the changed section values if persistence is available
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
const auto value = getItem(menuItem.getId()).getIndex();
|
||||
m_options->persistenceManager->SetValue(CreateKey(menuItem.getId()), value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#include "ui/NightColorSettingsMenu.h"
|
||||
|
||||
NightColorSettingsMenu::NightColorSettingsMenu(menu_options_t *options) : ColorSettingsMenu(options, "night")
|
||||
{
|
||||
}
|
||||
@@ -20,7 +20,7 @@ void ScreenSaver::initVehicles()
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSaver::update(const uint64_t dt)
|
||||
void ScreenSaver::Update(const uint64_t dt)
|
||||
{
|
||||
m_animationCounter += dt;
|
||||
m_lastSpawnTime += dt;
|
||||
@@ -214,7 +214,7 @@ ScreenSaver::Direction ScreenSaver::getRandomDirection()
|
||||
return (random() % 2 == 0) ? Direction::LEFT : Direction::RIGHT;
|
||||
}
|
||||
|
||||
void ScreenSaver::render()
|
||||
void ScreenSaver::Render()
|
||||
{
|
||||
// Clear screen with a black background
|
||||
u8g2_SetDrawColor(u8g2, 0);
|
||||
@@ -320,7 +320,7 @@ const unsigned char *ScreenSaver::getVehicleBitmap(const VehicleType type, const
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSaver::onButtonClicked(ButtonType button)
|
||||
void ScreenSaver::OnButtonClicked(ButtonType button)
|
||||
{
|
||||
if (m_options && m_options->popScreen)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ SplashScreen::SplashScreen(menu_options_t *options) : Widget(options->u8g2), m_o
|
||||
{
|
||||
}
|
||||
|
||||
void SplashScreen::update(const uint64_t dt)
|
||||
void SplashScreen::Update(const uint64_t dt)
|
||||
{
|
||||
splashTime += dt;
|
||||
if (splashTime > 100)
|
||||
@@ -20,7 +20,7 @@ void SplashScreen::update(const uint64_t dt)
|
||||
}
|
||||
}
|
||||
|
||||
void SplashScreen::render()
|
||||
void SplashScreen::Render()
|
||||
{
|
||||
u8g2_SetFont(u8g2, u8g2_font_DigitalDisco_tr);
|
||||
u8g2_DrawStr(u8g2, 28, u8g2->height / 2 - 10, "HO Anlage");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
idf_component_register(SRCS
|
||||
src/led_manager.cpp
|
||||
src/led_status.c
|
||||
src/led_strip_ws2812.c
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES
|
||||
insa
|
||||
@@ -8,4 +8,5 @@ idf_component_register(SRCS
|
||||
esp_event
|
||||
esp_timer
|
||||
persistence-manager
|
||||
simulator
|
||||
)
|
||||
|
||||
@@ -10,4 +10,10 @@ menu "Led Manager Configuration"
|
||||
default 2
|
||||
help
|
||||
The number of the status WLED pin.
|
||||
|
||||
config LED_STRIP_MAX_LEDS
|
||||
int "Maximum number of LEDs"
|
||||
default 500
|
||||
help
|
||||
The maximum number of LEDs that can be controlled.
|
||||
endmenu
|
||||
|
||||
12
firmware/components/led-manager/include/color.h
Normal file
12
firmware/components/led-manager/include/color.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
} rgb_t;
|
||||
|
||||
void interpolate_color(const rgb_t start_color, const rgb_t end_color, float fraction, rgb_t *out_color);
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum
|
||||
{
|
||||
EVENT_LED_ON,
|
||||
EVENT_LED_OFF,
|
||||
EVENT_LED_DAY,
|
||||
EVENT_LED_NIGHT,
|
||||
EVENT_LED_REFRESH
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
} led_event_data_t;
|
||||
|
||||
uint64_t wled_init();
|
||||
|
||||
uint64_t register_handler();
|
||||
|
||||
uint64_t send_event(uint32_t event, led_event_data_t *payload);
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "color.h"
|
||||
#include "esp_check.h"
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -14,14 +15,6 @@ typedef enum
|
||||
LED_MODE_BLINK
|
||||
} led_mode_t;
|
||||
|
||||
// Structure for an RGB color
|
||||
typedef struct
|
||||
{
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} rgb_t;
|
||||
|
||||
// This is the structure you pass from the outside to define a behavior
|
||||
typedef struct
|
||||
{
|
||||
@@ -31,28 +24,23 @@ typedef struct
|
||||
uint32_t off_time_ms; // Only relevant for BLINK
|
||||
} led_behavior_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/**
|
||||
* @brief Initializes the status manager and the LED strip.
|
||||
*
|
||||
* @param gpio_num GPIO where the data line of the LEDs is connected.
|
||||
* @return esp_err_t ESP_OK on success.
|
||||
*/
|
||||
esp_err_t led_status_init(int gpio_num);
|
||||
__BEGIN_DECLS
|
||||
/**
|
||||
* @brief Initializes the status manager and the LED strip.
|
||||
*
|
||||
* @param gpio_num GPIO where the data line of the LEDs is connected.
|
||||
* @return esp_err_t ESP_OK on success.
|
||||
*/
|
||||
esp_err_t led_status_init(int gpio_num);
|
||||
|
||||
/**
|
||||
* @brief Sets the lighting behavior for a single LED.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @param index Index of the LED (0 to STATUS_LED_COUNT - 1).
|
||||
* @param behavior The structure with the desired behavior.
|
||||
* @return esp_err_t ESP_OK on success, ESP_ERR_INVALID_ARG on invalid index.
|
||||
*/
|
||||
esp_err_t led_status_set_behavior(uint8_t index, led_behavior_t behavior);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @brief Sets the lighting behavior for a single LED.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @param index Index of the LED (0 to STATUS_LED_COUNT - 1).
|
||||
* @param behavior The structure with the desired behavior.
|
||||
* @return esp_err_t ESP_OK on success, ESP_ERR_INVALID_ARG on invalid index.
|
||||
*/
|
||||
esp_err_t led_status_set_behavior(uint8_t index, led_behavior_t behavior);
|
||||
__END_DECLS
|
||||
|
||||
18
firmware/components/led-manager/include/led_strip_ws2812.h
Normal file
18
firmware/components/led-manager/include/led_strip_ws2812.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "color.h"
|
||||
#include <esp_check.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LED_STATE_OFF,
|
||||
LED_STATE_DAY,
|
||||
LED_STATE_NIGHT,
|
||||
LED_STATE_SIMULATION,
|
||||
} led_state_t;
|
||||
|
||||
__BEGIN_DECLS
|
||||
esp_err_t led_strip_init(void);
|
||||
esp_err_t led_strip_update(led_state_t state, rgb_t color);
|
||||
__END_DECLS
|
||||
8
firmware/components/led-manager/src/color.c
Normal file
8
firmware/components/led-manager/src/color.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "color.h"
|
||||
|
||||
void interpolate_color(const rgb_t start_color, const rgb_t end_color, float fraction, rgb_t *out_color)
|
||||
{
|
||||
out_color->r = start_color.r + (end_color.r - start_color.r) * fraction;
|
||||
out_color->g = start_color.g + (end_color.g - start_color.g) * fraction;
|
||||
out_color->b = start_color.b + (end_color.b - start_color.b) * fraction;
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
#include "led_manager.h"
|
||||
|
||||
#include "common/ColorSettingsMenu.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "hal_esp32/PersistenceManager.h"
|
||||
#include "led_status.h"
|
||||
#include "led_strip.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
led_strip_handle_t led_strip;
|
||||
|
||||
static const int value = 125;
|
||||
static const uint32_t max_leds = 500;
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(LED_EVENTS_BASE);
|
||||
ESP_EVENT_DEFINE_BASE(LED_EVENTS_BASE);
|
||||
|
||||
esp_event_loop_handle_t loop_handle;
|
||||
|
||||
const char *TAG = "led_manager";
|
||||
|
||||
uint64_t wled_init(void)
|
||||
{
|
||||
led_strip_config_t strip_config = {
|
||||
.strip_gpio_num = CONFIG_WLED_DIN_PIN,
|
||||
.max_leds = max_leds,
|
||||
.led_model = LED_MODEL_WS2812,
|
||||
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
|
||||
.flags =
|
||||
{
|
||||
.invert_out = false,
|
||||
},
|
||||
};
|
||||
|
||||
led_strip_rmt_config_t rmt_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 0,
|
||||
.mem_block_symbols = 0,
|
||||
.flags =
|
||||
{
|
||||
.with_dma = true,
|
||||
},
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void event_handler(void *arg, esp_event_base_t base, int32_t id, void *event_data)
|
||||
{
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
uint8_t blue = 0;
|
||||
|
||||
if (id != EVENT_LED_OFF)
|
||||
{
|
||||
auto persistenceManager = PersistenceManager();
|
||||
persistenceManager.Load();
|
||||
|
||||
auto mode = persistenceManager.GetValue("light_mode", 0);
|
||||
auto light_mode = (mode == 0) ? "day" : "night";
|
||||
red = persistenceManager.GetValue(std::string(ColorSettingsMenuOptions::RED) + light_mode, value);
|
||||
green = persistenceManager.GetValue(std::string(ColorSettingsMenuOptions::GREEN) + light_mode, value);
|
||||
blue = persistenceManager.GetValue(std::string(ColorSettingsMenuOptions::BLUE) + light_mode, value);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < max_leds; i++)
|
||||
{
|
||||
led_strip_set_pixel(led_strip, i, red, green, blue);
|
||||
}
|
||||
led_strip_refresh(led_strip);
|
||||
|
||||
led_behavior_t led2_behavior = {
|
||||
.mode = LED_MODE_SOLID, .color = {.r = red, .g = green, .b = blue}, .on_time_ms = 0, .off_time_ms = 0};
|
||||
led_status_set_behavior(2, led2_behavior);
|
||||
}
|
||||
|
||||
uint64_t register_handler(void)
|
||||
{
|
||||
esp_event_loop_args_t loop_args = {
|
||||
.queue_size = 2, .task_name = "led_manager", .task_priority = 5, .task_stack_size = 4096, .task_core_id = 1};
|
||||
esp_event_loop_create(&loop_args, &loop_handle);
|
||||
|
||||
esp_event_handler_register_with(loop_handle, LED_EVENTS_BASE, ESP_EVENT_ANY_ID, event_handler, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint64_t send_event(uint32_t event, led_event_data_t *payload)
|
||||
{
|
||||
if (payload == nullptr)
|
||||
{
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_event_post_to(loop_handle, // Event loop handle
|
||||
LED_EVENTS_BASE, // Event base
|
||||
event, // Event ID (EVENT_LED_ON, EVENT_LED_OFF, etc.)
|
||||
payload, // Data pointer
|
||||
sizeof(led_event_data_t), // Data size
|
||||
portMAX_DELAY // Wait time
|
||||
);
|
||||
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE("LED", "Failed to post event: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -46,8 +46,8 @@ static void led_status_task(void *pvParameters)
|
||||
break;
|
||||
|
||||
case LED_MODE_SOLID:
|
||||
led_strip_set_pixel(led_strip, i, control->behavior.color.r, control->behavior.color.g,
|
||||
control->behavior.color.b);
|
||||
led_strip_set_pixel(led_strip, i, control->behavior.color.red, control->behavior.color.green,
|
||||
control->behavior.color.blue);
|
||||
break;
|
||||
|
||||
case LED_MODE_BLINK: {
|
||||
@@ -61,8 +61,8 @@ static void led_status_task(void *pvParameters)
|
||||
|
||||
if (control->is_on_in_blink)
|
||||
{
|
||||
led_strip_set_pixel(led_strip, i, control->behavior.color.r, control->behavior.color.g,
|
||||
control->behavior.color.b);
|
||||
led_strip_set_pixel(led_strip, i, control->behavior.color.red, control->behavior.color.green,
|
||||
control->behavior.color.blue);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -119,7 +119,7 @@ esp_err_t led_status_init(int gpio_num)
|
||||
}
|
||||
|
||||
// Start task
|
||||
xTaskCreate(led_status_task, "led_status_task", 2048, NULL, 5, NULL);
|
||||
xTaskCreate(led_status_task, "led_status_task", 2048, NULL, tskIDLE_PRIORITY + 1, NULL);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
111
firmware/components/led-manager/src/led_strip_ws2812.c
Normal file
111
firmware/components/led-manager/src/led_strip_ws2812.c
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "led_strip_ws2812.h"
|
||||
#include "color.h"
|
||||
#include "led_status.h"
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/task.h>
|
||||
#include <led_strip.h>
|
||||
#include <sdkconfig.h>
|
||||
|
||||
static const char *TAG = "led_strip";
|
||||
|
||||
static led_strip_handle_t led_strip;
|
||||
static QueueHandle_t led_command_queue;
|
||||
|
||||
static const uint32_t MAX_LEDS = CONFIG_LED_STRIP_MAX_LEDS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
led_state_t state;
|
||||
rgb_t color;
|
||||
} led_command_t;
|
||||
|
||||
static void set_all_pixels(const rgb_t color)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_LEDS; i++)
|
||||
{
|
||||
led_strip_set_pixel(led_strip, i, color.red, color.green, color.blue);
|
||||
}
|
||||
led_strip_refresh(led_strip);
|
||||
|
||||
led_behavior_t led2_behavior = {.mode = LED_MODE_SOLID,
|
||||
.color = {.red = color.red, .green = color.green, .blue = color.blue}};
|
||||
led_status_set_behavior(2, led2_behavior);
|
||||
}
|
||||
|
||||
void led_strip_task(void *pvParameters)
|
||||
{
|
||||
led_state_t current_state = LED_STATE_OFF;
|
||||
led_command_t cmd;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
TickType_t wait_ticks = (current_state == LED_STATE_SIMULATION) ? pdMS_TO_TICKS(50) : portMAX_DELAY;
|
||||
if (xQueueReceive(led_command_queue, &cmd, wait_ticks) == pdPASS)
|
||||
{
|
||||
current_state = cmd.state;
|
||||
}
|
||||
|
||||
rgb_t color;
|
||||
switch (current_state)
|
||||
{
|
||||
case LED_STATE_OFF:
|
||||
color = (rgb_t){.red = 0, .green = 0, .blue = 0};
|
||||
break;
|
||||
default:
|
||||
color = cmd.color;
|
||||
break;
|
||||
}
|
||||
|
||||
set_all_pixels(color);
|
||||
}
|
||||
};
|
||||
|
||||
esp_err_t led_strip_init(void)
|
||||
{
|
||||
led_strip_config_t strip_config = {
|
||||
.strip_gpio_num = CONFIG_WLED_DIN_PIN,
|
||||
.max_leds = MAX_LEDS,
|
||||
.led_model = LED_MODEL_WS2812,
|
||||
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
|
||||
.flags = {.invert_out = false},
|
||||
};
|
||||
|
||||
led_strip_rmt_config_t rmt_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 0,
|
||||
.mem_block_symbols = 0,
|
||||
.flags = {.with_dma = true},
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
|
||||
|
||||
led_command_queue = xQueueCreate(5, sizeof(led_command_t));
|
||||
if (led_command_queue == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to create command queue");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
xTaskCreate(led_strip_task, "led_strip_task", 4096, NULL, tskIDLE_PRIORITY + 1, NULL);
|
||||
|
||||
ESP_LOGI(TAG, "LED strip initialized");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t led_strip_update(led_state_t state, rgb_t color)
|
||||
{
|
||||
led_command_t cmd = {
|
||||
.state = state,
|
||||
.color = color,
|
||||
};
|
||||
|
||||
if (xQueueSend(led_command_queue, &cmd, pdMS_TO_TICKS(100)) != pdPASS)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to send command to LED manager queue");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
idf_component_register(SRCS
|
||||
"simulator.c"
|
||||
"storage.c"
|
||||
"src/simulator.c"
|
||||
"src/storage.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES
|
||||
led-manager
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
#include "esp_check.h"
|
||||
#include <stdint.h>
|
||||
|
||||
esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
void cleanup_light_items(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
// Configuration structure for the simulation
|
||||
typedef struct
|
||||
{
|
||||
#endif
|
||||
void simulate(void *args);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
void cleanup_light_items(void);
|
||||
void start_simulate_day(void);
|
||||
void start_simulate_night(void);
|
||||
void start_simulation_task(void);
|
||||
__END_DECLS
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
#include "simulator.h"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "led_status.h"
|
||||
#include "storage.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "simulator";
|
||||
|
||||
// The struct is extended with a 'next' pointer to form a linked list.
|
||||
typedef struct light_item_node_t
|
||||
{
|
||||
char time[5];
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
struct light_item_node_t *next;
|
||||
} light_item_node_t;
|
||||
|
||||
// Global pointers for the head and tail of the list.
|
||||
static light_item_node_t *head = NULL;
|
||||
static light_item_node_t *tail = NULL;
|
||||
|
||||
esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
// Allocate memory for a new node in PSRAM.
|
||||
light_item_node_t *new_node = (light_item_node_t *)heap_caps_malloc(sizeof(light_item_node_t), MALLOC_CAP_SPIRAM);
|
||||
if (new_node == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to allocate memory in PSRAM for new light_item_node_t.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Initialize the data of the new node.
|
||||
memcpy(new_node->time, time, sizeof(new_node->time));
|
||||
new_node->red = red;
|
||||
new_node->green = green;
|
||||
new_node->blue = blue;
|
||||
new_node->next = NULL;
|
||||
|
||||
// Append the new node to the end of the list.
|
||||
if (head == NULL)
|
||||
{
|
||||
// If the list is empty, the new node becomes both head and tail.
|
||||
head = new_node;
|
||||
tail = new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, append the new node to the end and update tail.
|
||||
tail->next = new_node;
|
||||
tail = new_node;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void cleanup_light_items(void)
|
||||
{
|
||||
light_item_node_t *current = head;
|
||||
light_item_node_t *next_node;
|
||||
|
||||
while (current != NULL)
|
||||
{
|
||||
next_node = current->next;
|
||||
heap_caps_free(current);
|
||||
current = next_node;
|
||||
}
|
||||
|
||||
head = NULL;
|
||||
tail = NULL;
|
||||
ESP_LOGI(TAG, "Cleaned up all light items.");
|
||||
}
|
||||
|
||||
void simulate(void *args)
|
||||
{
|
||||
ESP_LOGI(TAG, "Simulation task started with args: %p", args);
|
||||
|
||||
initialize_storage();
|
||||
load_file("/spiffs/schema_02.csv");
|
||||
|
||||
if (head == NULL)
|
||||
{
|
||||
ESP_LOGW(TAG, "Light schedule is empty. Simulation will not run.");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Starting simulation loop.");
|
||||
light_item_node_t *current_item = head;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (current_item == NULL)
|
||||
{
|
||||
current_item = head;
|
||||
ESP_LOGI(TAG, "Reached end of schedule, restarting from head.");
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Simulating time: %s -> R:%d, G:%d, B:%d", current_item->time, current_item->red,
|
||||
current_item->green, current_item->blue);
|
||||
led_behavior_t led1_behavior = {
|
||||
.mode = LED_MODE_SOLID,
|
||||
.color = {.r = current_item->red, .g = current_item->green, .b = current_item->blue},
|
||||
.on_time_ms = 0,
|
||||
.off_time_ms = 0};
|
||||
led_status_set_behavior(1, led1_behavior);
|
||||
|
||||
current_item = current_item->next;
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
cleanup_light_items();
|
||||
}
|
||||
245
firmware/components/simulator/src/simulator.c
Normal file
245
firmware/components/simulator/src/simulator.c
Normal file
@@ -0,0 +1,245 @@
|
||||
#include "simulator.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "led_strip_ws2812.h"
|
||||
#include "storage.h"
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "simulator";
|
||||
static char *time;
|
||||
|
||||
static char *time_to_string(int hhmm)
|
||||
{
|
||||
static char buffer[20];
|
||||
snprintf(buffer, sizeof(buffer), "%02d:%02d Uhr", hhmm / 100, hhmm % 100);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static TaskHandle_t simulation_task_handle = NULL;
|
||||
|
||||
// The struct is extended with a 'next' pointer to form a linked list.
|
||||
typedef struct light_item_node_t
|
||||
{
|
||||
char time[5];
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
struct light_item_node_t *next;
|
||||
} light_item_node_t;
|
||||
|
||||
// Global pointers for the head and tail of the list.
|
||||
static light_item_node_t *head = NULL;
|
||||
static light_item_node_t *tail = NULL;
|
||||
|
||||
char *get_time(void)
|
||||
{
|
||||
return time;
|
||||
}
|
||||
|
||||
esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
// Allocate memory for a new node in PSRAM.
|
||||
light_item_node_t *new_node = (light_item_node_t *)heap_caps_malloc(sizeof(light_item_node_t), MALLOC_CAP_SPIRAM);
|
||||
if (new_node == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to allocate memory in PSRAM for new light_item_node_t.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Initialize the data of the new node.
|
||||
memcpy(new_node->time, time, sizeof(new_node->time));
|
||||
new_node->red = red;
|
||||
new_node->green = green;
|
||||
new_node->blue = blue;
|
||||
new_node->next = NULL;
|
||||
|
||||
// Append the new node to the end of the list.
|
||||
if (head == NULL)
|
||||
{
|
||||
// If the list is empty, the new node becomes both head and tail.
|
||||
head = new_node;
|
||||
tail = new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, append the new node to the end and update tail.
|
||||
tail->next = new_node;
|
||||
tail = new_node;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void cleanup_light_items(void)
|
||||
{
|
||||
light_item_node_t *current = head;
|
||||
light_item_node_t *next_node;
|
||||
|
||||
while (current != NULL)
|
||||
{
|
||||
next_node = current->next;
|
||||
heap_caps_free(current);
|
||||
current = next_node;
|
||||
}
|
||||
|
||||
head = NULL;
|
||||
tail = NULL;
|
||||
ESP_LOGI(TAG, "Cleaned up all light items.");
|
||||
}
|
||||
|
||||
static void initialize_light_items(void)
|
||||
{
|
||||
if (head != NULL)
|
||||
{
|
||||
ESP_LOGI(TAG, "Light schedule already initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
initialize_storage();
|
||||
load_file("/spiffs/schema_02.csv");
|
||||
|
||||
if (head == NULL)
|
||||
{
|
||||
ESP_LOGW(TAG, "Light schedule is empty. Simulation will not run.");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static light_item_node_t *find_best_light_item_for_time(int hhmm)
|
||||
{
|
||||
light_item_node_t *best_item = NULL;
|
||||
light_item_node_t *current = head;
|
||||
int best_time = -1;
|
||||
|
||||
while (current != NULL)
|
||||
{
|
||||
int current_time = atoi(current->time);
|
||||
if (current_time <= hhmm && current_time > best_time)
|
||||
{
|
||||
best_time = current_time;
|
||||
best_item = current;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
if (best_item == NULL)
|
||||
{
|
||||
ESP_LOGW(TAG, "No suitable light item found for time up to %04d", hhmm);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, "Best light item for time %04d is %s", hhmm, best_item->time);
|
||||
}
|
||||
|
||||
return best_item;
|
||||
}
|
||||
|
||||
void start_simulate_day(void)
|
||||
{
|
||||
initialize_light_items();
|
||||
|
||||
light_item_node_t *current_item = find_best_light_item_for_time(1200);
|
||||
if (current_item != NULL)
|
||||
{
|
||||
led_strip_update(LED_STATE_DAY,
|
||||
(rgb_t){.red = current_item->red, .green = current_item->green, .blue = current_item->blue});
|
||||
}
|
||||
}
|
||||
|
||||
void start_simulate_night(void)
|
||||
{
|
||||
initialize_light_items();
|
||||
|
||||
light_item_node_t *current_item = find_best_light_item_for_time(0);
|
||||
if (current_item != NULL)
|
||||
{
|
||||
led_strip_update(LED_STATE_NIGHT,
|
||||
(rgb_t){.red = current_item->red, .green = current_item->green, .blue = current_item->blue});
|
||||
}
|
||||
}
|
||||
|
||||
void simulate_cycle(void *args)
|
||||
{
|
||||
simulation_config_t *config = (simulation_config_t *)args;
|
||||
int cycle_duration_minutes = config->cycle_duration_minutes;
|
||||
heap_caps_free(config);
|
||||
|
||||
if (cycle_duration_minutes <= 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Invalid cycle duration: %d minutes. Must be positive.", cycle_duration_minutes);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
initialize_light_items();
|
||||
|
||||
const int total_minutes_in_day = 24 * 60;
|
||||
long delay_ms = (long)cycle_duration_minutes * 60 * 1000 / total_minutes_in_day;
|
||||
ESP_LOGI(TAG, "Starting simulation of a 24h cycle over %d minutes. Each simulated minute will take %ld ms.",
|
||||
cycle_duration_minutes, delay_ms);
|
||||
|
||||
int current_minute_of_day = 0;
|
||||
light_item_node_t *last_item = NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int hours = current_minute_of_day / 60;
|
||||
int minutes = current_minute_of_day % 60;
|
||||
int hhmm = hours * 100 + minutes;
|
||||
time = time_to_string(hhmm);
|
||||
|
||||
light_item_node_t *current_item = find_best_light_item_for_time(hhmm);
|
||||
|
||||
if (current_item != NULL && current_item != last_item)
|
||||
{
|
||||
ESP_LOGI(TAG, "Simulating time: %02d:%02d -> Closest schedule is %s. R:%d, G:%d, B:%d", hours, minutes,
|
||||
current_item->time, current_item->red, current_item->green, current_item->blue);
|
||||
led_strip_update(
|
||||
LED_STATE_SIMULATION,
|
||||
(rgb_t){.red = current_item->red, .green = current_item->green, .blue = current_item->blue});
|
||||
last_item = current_item;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(delay_ms));
|
||||
|
||||
current_minute_of_day++;
|
||||
if (current_minute_of_day >= total_minutes_in_day)
|
||||
{
|
||||
current_minute_of_day = 0;
|
||||
ESP_LOGI(TAG, "Simulation cycle restarting.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void start_simulation_task(void)
|
||||
{
|
||||
if (simulation_task_handle != NULL)
|
||||
{
|
||||
vTaskDelete(simulation_task_handle);
|
||||
simulation_task_handle = NULL;
|
||||
}
|
||||
|
||||
simulation_config_t *config =
|
||||
(simulation_config_t *)heap_caps_malloc(sizeof(simulation_config_t), MALLOC_CAP_SPIRAM);
|
||||
if (config == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for simulation config.");
|
||||
return;
|
||||
}
|
||||
|
||||
config->cycle_duration_minutes = 15;
|
||||
|
||||
if (xTaskCreate(simulate_cycle, "simulate_cycle", 4096, (void *)config, tskIDLE_PRIORITY + 1,
|
||||
&simulation_task_handle) != pdPASS)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to create simulation task.");
|
||||
heap_caps_free(config);
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ static void init_ui(void)
|
||||
});
|
||||
|
||||
u8g2_ClearBuffer(&u8g2);
|
||||
m_widget->render();
|
||||
m_widget->Render();
|
||||
u8g2_SendBuffer(&u8g2);
|
||||
}
|
||||
|
||||
@@ -126,27 +126,27 @@ static void handle_button(uint8_t button)
|
||||
switch (button)
|
||||
{
|
||||
case 1:
|
||||
m_widget->onButtonClicked(ButtonType::UP);
|
||||
m_widget->OnButtonClicked(ButtonType::UP);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_widget->onButtonClicked(ButtonType::LEFT);
|
||||
m_widget->OnButtonClicked(ButtonType::LEFT);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
m_widget->onButtonClicked(ButtonType::RIGHT);
|
||||
m_widget->OnButtonClicked(ButtonType::RIGHT);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
m_widget->onButtonClicked(ButtonType::DOWN);
|
||||
m_widget->OnButtonClicked(ButtonType::DOWN);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
m_widget->onButtonClicked(ButtonType::BACK);
|
||||
m_widget->OnButtonClicked(ButtonType::BACK);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
m_widget->onButtonClicked(ButtonType::SELECT);
|
||||
m_widget->OnButtonClicked(ButtonType::SELECT);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -160,8 +160,10 @@ void app_task(void *args)
|
||||
{
|
||||
if (i2c_bus_scan_and_check() != ESP_OK)
|
||||
{
|
||||
led_behavior_t led0_behavior = {
|
||||
.mode = LED_MODE_BLINK, .color = {.r = 50, .g = 0, .b = 0}, .on_time_ms = 1000, .off_time_ms = 500};
|
||||
led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK,
|
||||
.color = {.red = 50, .green = 0, .blue = 0},
|
||||
.on_time_ms = 1000,
|
||||
.off_time_ms = 500};
|
||||
led_status_set_behavior(0, led0_behavior);
|
||||
|
||||
ESP_LOGE(TAG, "Display not found on I2C bus");
|
||||
@@ -192,8 +194,8 @@ void app_task(void *args)
|
||||
|
||||
uint64_t deltaMs = delta / 1000;
|
||||
|
||||
m_widget->update(deltaMs);
|
||||
m_widget->render();
|
||||
m_widget->Update(deltaMs);
|
||||
m_widget->Render();
|
||||
|
||||
m_inactivityTracker->update(deltaMs);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
void setup_buttons(void);
|
||||
void cleanup_buttons(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
void setup_buttons(void);
|
||||
void cleanup_buttons(void);
|
||||
__END_DECLS
|
||||
|
||||
@@ -70,23 +70,18 @@ typedef struct
|
||||
.reset = U8G2_ESP32_HAL_UNDEFINED, \
|
||||
.dc = U8G2_ESP32_HAL_UNDEFINED}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/**
|
||||
* Initialize the HAL with the given configuration.
|
||||
*
|
||||
* @see u8g2_esp32_hal_t
|
||||
* @see U8G2_ESP32_HAL_DEFAULT
|
||||
*/
|
||||
void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param);
|
||||
uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
__BEGIN_DECLS
|
||||
/**
|
||||
* Initialize the HAL with the given configuration.
|
||||
*
|
||||
* @see u8g2_esp32_hal_t
|
||||
* @see U8G2_ESP32_HAL_DEFAULT
|
||||
*/
|
||||
void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param);
|
||||
uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
__END_DECLS
|
||||
#endif /* U8G2_ESP32_HAL_H_ */
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
#define I2C_MASTER_SDA_PIN ((gpio_num_t)CONFIG_DISPLAY_SDA_PIN)
|
||||
#define I2C_MASTER_SCL_PIN ((gpio_num_t)CONFIG_DISPLAY_SCL_PIN)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
esp_err_t i2c_bus_scan_and_check(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
__BEGIN_DECLS
|
||||
esp_err_t i2c_bus_scan_and_check(void);
|
||||
__END_DECLS
|
||||
|
||||
@@ -1,52 +1,45 @@
|
||||
#include "app_task.h"
|
||||
#include "ble_manager.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_insights.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "color.h"
|
||||
#include "hal_esp32/PersistenceManager.h"
|
||||
#include "led_manager.h"
|
||||
#include "led_status.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "led_strip_ws2812.h"
|
||||
#include "simulator.h"
|
||||
#include "wifi_manager.h"
|
||||
#include <ble_manager.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_insights.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <sdkconfig.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
__BEGIN_DECLS
|
||||
void app_main(void)
|
||||
{
|
||||
#endif
|
||||
void app_main(void)
|
||||
// Initialize NVS
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||
{
|
||||
// Initialize NVS
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
}
|
||||
|
||||
led_status_init(CONFIG_STATUS_WLED_PIN);
|
||||
|
||||
wled_init();
|
||||
|
||||
register_handler();
|
||||
|
||||
xTaskCreatePinnedToCore(app_task, "app_task", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1);
|
||||
xTaskCreatePinnedToCore(simulate, "simulate", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1);
|
||||
// xTaskCreatePinnedToCore(ble_manager_task, "ble_manager", 4096, NULL, tskIDLE_PRIORITY + 1, NULL,
|
||||
// portNUM_PROCESSORS - 1);
|
||||
|
||||
auto persistence = PersistenceManager();
|
||||
persistence.Load();
|
||||
|
||||
if (persistence.GetValue("light_active", false))
|
||||
{
|
||||
led_event_data_t payload = {.value = 42};
|
||||
send_event(EVENT_LED_ON, &payload);
|
||||
}
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
}
|
||||
|
||||
auto persistence = PersistenceManager();
|
||||
persistence.Load();
|
||||
|
||||
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(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{});
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
@@ -206,8 +206,8 @@ void Device::DrawScreen(const uint64_t dt) const
|
||||
|
||||
if (m_widget != nullptr)
|
||||
{
|
||||
m_widget->update(dt);
|
||||
m_widget->render();
|
||||
m_widget->Update(dt);
|
||||
m_widget->Render();
|
||||
}
|
||||
|
||||
RenderU8G2();
|
||||
@@ -257,7 +257,7 @@ void Device::OnButtonClicked(const ButtonType button) const
|
||||
|
||||
if (m_widget != nullptr)
|
||||
{
|
||||
m_widget->onButtonClicked(button);
|
||||
m_widget->OnButtonClicked(button);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user