195 lines
6.3 KiB
C++
195 lines
6.3 KiB
C++
#pragma once
|
|
|
|
#include "WidgetConfig.hpp"
|
|
#include "widgets/Widget.hpp"
|
|
#include "lvgl.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/queue.h"
|
|
#include "freertos/portmacro.h"
|
|
#include <array>
|
|
#include <ctime>
|
|
#include <memory>
|
|
|
|
enum class KnxTimeType : uint8_t {
|
|
TIME = 0,
|
|
DATE = 1,
|
|
DATETIME = 2,
|
|
};
|
|
|
|
class WidgetManager {
|
|
public:
|
|
static WidgetManager& instance();
|
|
|
|
// Initialize (load config from SD card)
|
|
void init();
|
|
|
|
// Build/rebuild all widgets from current config
|
|
// Call this after loading or when user clicks "Save" in web editor
|
|
void applyConfig();
|
|
|
|
// Get current config for web editor (JSON)
|
|
void getConfigJson(char* buf, size_t bufSize) const;
|
|
|
|
// Update config from web editor (JSON) - does NOT apply immediately
|
|
bool updateConfigFromJson(const char* json);
|
|
|
|
// Save current config to SD card and apply to display
|
|
void saveAndApply();
|
|
|
|
// Reset to factory defaults
|
|
void resetToDefaults();
|
|
|
|
// Periodic tasks (standby handling)
|
|
void loop();
|
|
|
|
// User activity (resets standby timer)
|
|
void onUserActivity();
|
|
|
|
// Update widgets displaying system time
|
|
void updateSystemTimeWidgets();
|
|
|
|
// Thread-safe KNX updates (queued to UI thread)
|
|
void onKnxValue(uint16_t groupAddr, float value, TextSource source);
|
|
void onKnxValue(uint16_t groupAddr, float value);
|
|
void onKnxSwitch(uint16_t groupAddr, bool value);
|
|
void onKnxText(uint16_t groupAddr, const char* text);
|
|
void onKnxTime(uint16_t groupAddr, const struct tm& value, KnxTimeType type);
|
|
|
|
// Button action handler
|
|
void handleButtonAction(const WidgetConfig& cfg, lv_obj_t* target);
|
|
void goBack();
|
|
|
|
// Direct config access
|
|
GuiConfig& getConfig() { return config_; }
|
|
const GuiConfig& getConfig() const { return config_; }
|
|
const ScreenConfig* currentScreen() const;
|
|
|
|
private:
|
|
WidgetManager();
|
|
~WidgetManager() = default;
|
|
WidgetManager(const WidgetManager&) = delete;
|
|
WidgetManager& operator=(const WidgetManager&) = delete;
|
|
|
|
static constexpr size_t UI_EVENT_QUEUE_LEN = 16;
|
|
static constexpr size_t UI_EVENT_TEXT_LEN = MAX_TEXT_LEN;
|
|
|
|
enum class UiEventType : uint8_t {
|
|
KNX_VALUE = 0,
|
|
KNX_SWITCH = 1,
|
|
KNX_TEXT = 2,
|
|
KNX_TIME = 3,
|
|
};
|
|
|
|
struct UiEvent {
|
|
UiEventType type;
|
|
uint16_t groupAddr;
|
|
TextSource textSource;
|
|
float value;
|
|
bool state;
|
|
char text[UI_EVENT_TEXT_LEN];
|
|
KnxTimeType timeType;
|
|
struct tm timeValue;
|
|
};
|
|
|
|
static constexpr size_t KNX_CACHE_SIZE = MAX_WIDGETS * MAX_SCREENS;
|
|
|
|
struct KnxNumericCacheEntry {
|
|
uint16_t groupAddr = 0;
|
|
TextSource source = TextSource::STATIC;
|
|
float value = 0.0f;
|
|
bool valid = false;
|
|
};
|
|
|
|
struct KnxSwitchCacheEntry {
|
|
uint16_t groupAddr = 0;
|
|
bool value = false;
|
|
bool valid = false;
|
|
};
|
|
|
|
struct KnxTextCacheEntry {
|
|
uint16_t groupAddr = 0;
|
|
char text[MAX_TEXT_LEN] = {};
|
|
bool valid = false;
|
|
};
|
|
|
|
struct KnxTimeCacheEntry {
|
|
uint16_t groupAddr = 0;
|
|
KnxTimeType type = KnxTimeType::TIME;
|
|
struct tm value = {};
|
|
bool valid = false;
|
|
};
|
|
|
|
void loadFromSdCard();
|
|
void saveToSdCard();
|
|
void destroyAllWidgets();
|
|
void createAllWidgets(const ScreenConfig& screen, lv_obj_t* parent);
|
|
bool enqueueUiEvent(const UiEvent& event);
|
|
void processUiQueue();
|
|
void applyCachedValuesToWidgets();
|
|
void applyKnxValue(uint16_t groupAddr, float value, TextSource source);
|
|
void applyKnxSwitch(uint16_t groupAddr, bool value);
|
|
void applyKnxText(uint16_t groupAddr, const char* text);
|
|
void applyKnxTime(uint16_t groupAddr, const struct tm& value, KnxTimeType type);
|
|
void cacheKnxValue(uint16_t groupAddr, TextSource source, float value);
|
|
void cacheKnxSwitch(uint16_t groupAddr, bool value);
|
|
void cacheKnxText(uint16_t groupAddr, const char* text);
|
|
void cacheKnxTime(uint16_t groupAddr, KnxTimeType type, const struct tm& value);
|
|
bool getCachedKnxValue(uint16_t groupAddr, TextSource source, float* out) const;
|
|
bool getCachedKnxSwitch(uint16_t groupAddr, bool* out) const;
|
|
bool getCachedKnxText(uint16_t groupAddr, char* out, size_t outSize) const;
|
|
bool getCachedKnxTime(uint16_t groupAddr, KnxTimeType type, struct tm* out) const;
|
|
static bool isNumericTextSource(TextSource source);
|
|
void refreshChartWidgetsLocked();
|
|
void refreshChartWidgets();
|
|
|
|
void createDefaultConfig();
|
|
void applyScreen(uint8_t screenId);
|
|
void applyScreenLocked(uint8_t screenId);
|
|
void showScreenLocked(uint8_t screenId);
|
|
void showModalScreen(const ScreenConfig& screen);
|
|
void showModalScreenLocked(const ScreenConfig& screen);
|
|
void closeModal();
|
|
void closeModalLocked();
|
|
void goBackLocked();
|
|
void enterStandby();
|
|
ScreenConfig* activeScreen();
|
|
const ScreenConfig* activeScreen() const;
|
|
|
|
static constexpr const char* CONFIG_FILE = "/sdcard/lvgl.json";
|
|
static constexpr int64_t NAV_DELAY_US = 10 * 1000; // 10ms delay (almost immediate)
|
|
|
|
GuiConfig config_;
|
|
uint8_t activeScreenId_ = 0;
|
|
uint8_t previousScreenId_ = 0xFF;
|
|
uint8_t standbyReturnScreenId_ = 0xFF;
|
|
uint8_t modalScreenId_ = 0xFF;
|
|
bool standbyActive_ = false;
|
|
bool standbyWakePending_ = false;
|
|
uint8_t standbyWakeTarget_ = 0xFF;
|
|
bool navPending_ = false;
|
|
bool chartRefreshPending_ = false;
|
|
bool nightMode_ = false;
|
|
ButtonAction navAction_ = ButtonAction::KNX;
|
|
uint8_t navTargetScreen_ = 0xFF;
|
|
int64_t navRequestUs_ = 0;
|
|
int64_t lastActivityUs_ = 0;
|
|
int64_t lastSystemTimeUpdateUs_ = 0;
|
|
|
|
// Runtime widget instances (indexed by widget ID)
|
|
std::array<std::unique_ptr<Widget>, 256> widgets_;
|
|
lv_obj_t* screen_ = nullptr;
|
|
lv_obj_t* modalContainer_ = nullptr;
|
|
lv_obj_t* modalDimmer_ = nullptr;
|
|
QueueHandle_t uiQueue_ = nullptr;
|
|
|
|
std::array<KnxNumericCacheEntry, KNX_CACHE_SIZE> knxNumericCache_ = {};
|
|
std::array<KnxSwitchCacheEntry, KNX_CACHE_SIZE> knxSwitchCache_ = {};
|
|
std::array<KnxTextCacheEntry, KNX_CACHE_SIZE> knxTextCache_ = {};
|
|
std::array<KnxTimeCacheEntry, KNX_CACHE_SIZE> knxTimeCache_ = {};
|
|
size_t knxNumericCacheNext_ = 0;
|
|
size_t knxSwitchCacheNext_ = 0;
|
|
size_t knxTextCacheNext_ = 0;
|
|
size_t knxTimeCacheNext_ = 0;
|
|
mutable portMUX_TYPE knxCacheMux_ = {};
|
|
};
|