322 lines
10 KiB
C++
322 lines
10 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
|
|
// Maximum number of widgets
|
|
static constexpr size_t MAX_WIDGETS = 64;
|
|
static constexpr size_t MAX_SCREENS = 8;
|
|
static constexpr size_t MAX_TEXT_LEN = 32;
|
|
static constexpr size_t MAX_SCREEN_NAME_LEN = 24;
|
|
static constexpr size_t MAX_BG_IMAGE_PATH_LEN = 48;
|
|
static constexpr size_t CHART_MAX_SERIES = 3;
|
|
static constexpr size_t MAX_CONDITIONS = 3;
|
|
static constexpr size_t MAX_FORMAT_LEN = 16; // Shorter format strings for left/right values
|
|
static constexpr size_t MAX_SUBBUTTONS = 6; // Sub-buttons for RoomCard
|
|
|
|
enum class WidgetType : uint8_t {
|
|
LABEL = 0,
|
|
BUTTON = 1,
|
|
LED = 2,
|
|
ICON = 3,
|
|
TABVIEW = 4,
|
|
TABPAGE = 5,
|
|
POWERFLOW = 6,
|
|
POWERNODE = 7,
|
|
POWERLINK = 8,
|
|
CHART = 9,
|
|
CLOCK = 10,
|
|
ROOMCARD = 11,
|
|
};
|
|
|
|
enum class IconPosition : uint8_t {
|
|
LEFT = 0,
|
|
RIGHT = 1,
|
|
TOP = 2,
|
|
BOTTOM = 3,
|
|
};
|
|
|
|
enum class ScreenMode : uint8_t {
|
|
FULLSCREEN = 0,
|
|
MODAL = 1,
|
|
};
|
|
|
|
enum class BgImageMode : uint8_t {
|
|
NONE = 0,
|
|
STRETCH = 1,
|
|
CENTER = 2,
|
|
TILE = 3,
|
|
};
|
|
|
|
enum class ButtonAction : uint8_t {
|
|
KNX = 0,
|
|
JUMP = 1,
|
|
BACK = 2,
|
|
};
|
|
|
|
enum class ChartPeriod : uint8_t {
|
|
HOUR_1 = 0,
|
|
HOUR_3 = 1,
|
|
HOUR_5 = 2,
|
|
HOUR_12 = 3,
|
|
HOUR_24 = 4,
|
|
MONTH_1 = 5,
|
|
};
|
|
|
|
// Text source: static text or KNX group address
|
|
enum class TextSource : uint8_t {
|
|
STATIC = 0, // Static text
|
|
KNX_DPT_TEMP = 1, // KNX Temperature (DPT 9.001)
|
|
KNX_DPT_SWITCH = 2, // KNX Switch (DPT 1.001)
|
|
KNX_DPT_PERCENT = 3, // KNX Percent (DPT 5.001)
|
|
KNX_DPT_TEXT = 4, // KNX Text (DPT 16.000)
|
|
KNX_DPT_POWER = 5, // KNX Power (DPT 14.056)
|
|
KNX_DPT_ENERGY = 6, // KNX Energy (DPT 13.013)
|
|
KNX_DPT_DECIMALFACTOR = 7, // KNX Decimal Factor (DPT 5.005)
|
|
KNX_DPT_TIME = 8, // KNX Time of day (DPT 10.001)
|
|
KNX_DPT_DATE = 9, // KNX Date (DPT 11.001)
|
|
KNX_DPT_DATETIME = 10, // KNX DateTime (DPT 19.001)
|
|
SYSTEM_TIME = 11, // System Time (RTC)
|
|
SYSTEM_DATE = 12, // System Date (RTC)
|
|
SYSTEM_DATETIME = 13, // System DateTime (RTC)
|
|
};
|
|
|
|
enum class TextAlign : uint8_t {
|
|
LEFT = 0,
|
|
CENTER = 1,
|
|
RIGHT = 2,
|
|
};
|
|
|
|
// Color as RGB888
|
|
struct Color {
|
|
uint8_t r, g, b;
|
|
|
|
uint32_t toLvColor() const {
|
|
return (r << 16) | (g << 8) | b;
|
|
}
|
|
|
|
static Color fromHex(uint32_t hex) {
|
|
return {
|
|
.r = static_cast<uint8_t>((hex >> 16) & 0xFF),
|
|
.g = static_cast<uint8_t>((hex >> 8) & 0xFF),
|
|
.b = static_cast<uint8_t>(hex & 0xFF)
|
|
};
|
|
}
|
|
};
|
|
|
|
// Condition operator for conditional styling
|
|
enum class ConditionOp : uint8_t {
|
|
LESS = 0, // value < threshold
|
|
LESS_EQUAL = 1, // value <= threshold
|
|
EQUAL = 2, // value == threshold
|
|
GREATER_EQUAL = 3, // value >= threshold
|
|
GREATER = 4, // value > threshold
|
|
NOT_EQUAL = 5, // value != threshold
|
|
};
|
|
|
|
// Which KNX address to use for condition evaluation
|
|
enum class ConditionSource : uint8_t {
|
|
PRIMARY = 0, // knxAddress (bottom value)
|
|
SECONDARY = 1, // knxAddress2 (left value)
|
|
TERTIARY = 2, // knxAddress3 (right value)
|
|
};
|
|
|
|
// Style to apply when condition is met
|
|
struct ConditionStyle {
|
|
uint32_t iconCodepoint; // 0 = don't change icon
|
|
Color textColor;
|
|
Color bgColor;
|
|
uint8_t bgOpacity;
|
|
uint8_t flags; // Bits: 0=useTextColor, 1=useBgColor, 2=useBgOpacity, 3=hide
|
|
|
|
static constexpr uint8_t FLAG_USE_TEXT_COLOR = 0x01;
|
|
static constexpr uint8_t FLAG_USE_BG_COLOR = 0x02;
|
|
static constexpr uint8_t FLAG_USE_BG_OPACITY = 0x04;
|
|
static constexpr uint8_t FLAG_HIDE = 0x08;
|
|
};
|
|
|
|
// A single style condition
|
|
struct StyleCondition {
|
|
float threshold; // 4 bytes
|
|
ConditionOp op; // 1 byte
|
|
ConditionSource source; // 1 byte - which value to check
|
|
uint8_t priority; // 1 byte (lower = higher priority)
|
|
ConditionStyle style; // 12 bytes
|
|
bool enabled; // 1 byte
|
|
// Total: 20 bytes per condition
|
|
};
|
|
|
|
// Sub-button position around RoomCard bubble (8 positions, 45° apart)
|
|
enum class SubButtonPosition : uint8_t {
|
|
TOP = 0,
|
|
TOP_RIGHT = 1,
|
|
RIGHT = 2,
|
|
BOTTOM_RIGHT = 3,
|
|
BOTTOM = 4,
|
|
BOTTOM_LEFT = 5,
|
|
LEFT = 6,
|
|
TOP_LEFT = 7,
|
|
};
|
|
|
|
// Sub-button action type
|
|
enum class SubButtonAction : uint8_t {
|
|
TOGGLE_KNX = 0, // Toggle KNX switch
|
|
NAVIGATE = 1, // Navigate to screen
|
|
};
|
|
|
|
// Sub-button configuration for RoomCard (20 bytes)
|
|
struct SubButtonConfig {
|
|
uint32_t iconCodepoint; // 4 bytes - Icon codepoint
|
|
uint16_t knxAddrRead; // 2 bytes - KNX address to read status
|
|
uint16_t knxAddrWrite; // 2 bytes - KNX address to write on click
|
|
Color colorOn; // 3 bytes - Color when ON
|
|
Color colorOff; // 3 bytes - Color when OFF
|
|
SubButtonPosition position; // 1 byte - Position around bubble
|
|
SubButtonAction action; // 1 byte - Action type
|
|
uint8_t targetScreen; // 1 byte - Target screen for navigate
|
|
bool enabled; // 1 byte - Is this sub-button active?
|
|
uint8_t _padding[2]; // 2 bytes - Alignment padding
|
|
// Total: 20 bytes per SubButton
|
|
};
|
|
|
|
// Shadow configuration
|
|
struct ShadowConfig {
|
|
int8_t offsetX;
|
|
int8_t offsetY;
|
|
uint8_t blur;
|
|
uint8_t spread;
|
|
Color color;
|
|
bool enabled;
|
|
};
|
|
|
|
// Widget configuration
|
|
struct WidgetConfig {
|
|
// Basic properties
|
|
uint8_t id; // Unique ID (0-255)
|
|
WidgetType type;
|
|
int16_t x, y;
|
|
int16_t width, height;
|
|
bool visible;
|
|
|
|
// Text properties
|
|
TextSource textSource;
|
|
char text[MAX_TEXT_LEN]; // Static text or format string
|
|
uint16_t knxAddress; // KNX group address (GA) for read binding
|
|
uint8_t fontSize; // Font size index (0=14, 1=18, 2=22, 3=28, 4=36, 5=48)
|
|
uint8_t textAlign; // TextAlign: 0=left, 1=center, 2=right
|
|
bool isContainer; // For buttons: use as container (no internal label/icon)
|
|
|
|
// Colors
|
|
Color textColor;
|
|
Color bgColor;
|
|
uint8_t bgOpacity; // 0-255
|
|
uint8_t borderRadius;
|
|
|
|
// Shadow
|
|
ShadowConfig shadow;
|
|
|
|
// Button specific
|
|
bool isToggle; // For buttons: toggle mode
|
|
uint16_t knxAddressWrite; // KNX group address (GA) to write on click
|
|
ButtonAction action; // Button action (KNX, Jump, Back)
|
|
uint8_t targetScreen; // Target screen ID for jump
|
|
|
|
// Icon properties (for Label, Button, Icon widgets)
|
|
uint32_t iconCodepoint; // Unicode codepoint (0 = no icon)
|
|
uint8_t iconPosition; // IconPosition: 0=left, 1=right, 2=top, 3=bottom
|
|
uint8_t iconSize; // Font size index (0-5), same as fontSize
|
|
int8_t iconGap; // Gap between icon and text (px)
|
|
|
|
// Hierarchy
|
|
int8_t parentId; // ID of parent widget (-1 = root/screen)
|
|
|
|
// Chart properties
|
|
uint8_t chartPeriod;
|
|
uint8_t chartSeriesCount;
|
|
uint16_t chartKnxAddress[CHART_MAX_SERIES];
|
|
TextSource chartTextSource[CHART_MAX_SERIES];
|
|
Color chartSeriesColor[CHART_MAX_SERIES];
|
|
|
|
// Secondary KNX address (for PowerNode LEFT value)
|
|
uint16_t knxAddress2;
|
|
TextSource textSource2;
|
|
char text2[MAX_FORMAT_LEN]; // Format string for left value (short)
|
|
|
|
// Tertiary KNX address (for PowerNode RIGHT value)
|
|
uint16_t knxAddress3;
|
|
TextSource textSource3;
|
|
char text3[MAX_FORMAT_LEN]; // Format string for right value (short)
|
|
|
|
// Conditional styling
|
|
uint8_t conditionCount;
|
|
StyleCondition conditions[MAX_CONDITIONS];
|
|
|
|
// RoomCard sub-buttons
|
|
uint8_t subButtonCount;
|
|
uint8_t subButtonSize; // Sub-button size in pixels (default 40)
|
|
uint8_t subButtonDistance; // Distance from center in pixels (default 80)
|
|
SubButtonConfig subButtons[MAX_SUBBUTTONS];
|
|
|
|
// Serialization size (fixed for NVS storage)
|
|
// 197 + 1 (subButtonCount) + 1 (subButtonSize) + 1 (subButtonDistance) + 120 (6 subButtons * 20) = 320
|
|
static constexpr size_t SERIALIZED_SIZE = 320;
|
|
|
|
void serialize(uint8_t* buf) const;
|
|
void deserialize(const uint8_t* buf);
|
|
|
|
// Create default label
|
|
static WidgetConfig createLabel(uint8_t id, int16_t x, int16_t y, const char* text);
|
|
|
|
// Create KNX-bound label
|
|
static WidgetConfig createKnxLabel(uint8_t id, int16_t x, int16_t y,
|
|
TextSource source, uint16_t knxAddr, const char* format);
|
|
|
|
// Create button
|
|
static WidgetConfig createButton(uint8_t id, int16_t x, int16_t y,
|
|
const char* text, uint16_t knxAddrWrite, bool toggle);
|
|
};
|
|
|
|
// Screen configuration (holds all widgets)
|
|
struct ScreenConfig {
|
|
uint8_t id;
|
|
char name[MAX_SCREEN_NAME_LEN];
|
|
ScreenMode mode;
|
|
Color backgroundColor;
|
|
char bgImagePath[MAX_BG_IMAGE_PATH_LEN]; // Background image path (e.g., "/images/bg.png")
|
|
BgImageMode bgImageMode; // 0=none, 1=stretch, 2=center, 3=tile
|
|
uint8_t widgetCount;
|
|
WidgetConfig widgets[MAX_WIDGETS];
|
|
|
|
// Modal-specific properties (only used when mode == MODAL)
|
|
int16_t modalX; // Modal position X (0 = centered)
|
|
int16_t modalY; // Modal position Y (0 = centered)
|
|
int16_t modalWidth; // Modal width (0 = auto from content)
|
|
int16_t modalHeight; // Modal height (0 = auto from content)
|
|
uint8_t modalBorderRadius;
|
|
bool modalDimBackground; // Dim the background behind modal
|
|
|
|
void clear(uint8_t newId = 0, const char* newName = nullptr);
|
|
int addWidget(const WidgetConfig& widget); // Returns widget ID or -1
|
|
bool removeWidget(uint8_t id);
|
|
WidgetConfig* findWidget(uint8_t id);
|
|
const WidgetConfig* findWidget(uint8_t id) const;
|
|
};
|
|
|
|
struct GuiConfig {
|
|
uint8_t screenCount;
|
|
ScreenConfig screens[MAX_SCREENS];
|
|
uint8_t startScreenId;
|
|
bool standbyEnabled;
|
|
uint8_t standbyScreenId;
|
|
uint16_t standbyMinutes;
|
|
uint16_t knxTimeAddress;
|
|
uint16_t knxDateAddress;
|
|
uint16_t knxDateTimeAddress;
|
|
uint16_t knxNightModeAddress;
|
|
|
|
void clear();
|
|
ScreenConfig* findScreen(uint8_t id);
|
|
const ScreenConfig* findScreen(uint8_t id) const;
|
|
};
|