fixes that made it work
This commit is contained in:
4
components/dashboard_ui/CMakeLists.txt
Normal file
4
components/dashboard_ui/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(
|
||||
SRCS "dashboard_ui.c"
|
||||
REQUIRES lvgl__lvgl ws_client
|
||||
INCLUDE_DIRS "./")
|
||||
318
components/dashboard_ui/dashboard_ui.c
Normal file
318
components/dashboard_ui/dashboard_ui.c
Normal file
@@ -0,0 +1,318 @@
|
||||
#include "dashboard_ui.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ---------- Layout constants ---------- */
|
||||
#define SCREEN_W 400
|
||||
#define SCREEN_H 300
|
||||
#define TOP_BAR_H 24
|
||||
#define STATS_H 80
|
||||
#define MID_H 140
|
||||
#define BOT_H 32
|
||||
|
||||
/* ---------- Static widget handles ---------- */
|
||||
|
||||
/* Top bar */
|
||||
static lv_obj_t *lbl_ip;
|
||||
static lv_obj_t *lbl_batt;
|
||||
static lv_obj_t *lbl_time;
|
||||
static lv_obj_t *lbl_ws;
|
||||
|
||||
/* Pi stats bars + labels */
|
||||
static lv_obj_t *bar_cpu;
|
||||
static lv_obj_t *lbl_cpu_val;
|
||||
static lv_obj_t *bar_ram;
|
||||
static lv_obj_t *lbl_ram_val;
|
||||
static lv_obj_t *bar_disk;
|
||||
static lv_obj_t *lbl_disk_val;
|
||||
static lv_obj_t *lbl_cpu_temp;
|
||||
|
||||
/* Services table */
|
||||
static lv_obj_t *tbl_services;
|
||||
|
||||
/* Local sensors */
|
||||
static lv_obj_t *lbl_room_temp;
|
||||
static lv_obj_t *lbl_room_humi;
|
||||
static lv_obj_t *lbl_local_batt;
|
||||
static lv_obj_t *lbl_uptime;
|
||||
|
||||
/* Network */
|
||||
static lv_obj_t *lbl_net;
|
||||
|
||||
/* ---------- Style ---------- */
|
||||
static lv_style_t style_bar_bg;
|
||||
static lv_style_t style_bar_ind;
|
||||
|
||||
static void init_styles(void)
|
||||
{
|
||||
/* Bar background: white with 1px black border */
|
||||
lv_style_init(&style_bar_bg);
|
||||
lv_style_set_bg_color(&style_bar_bg, lv_color_white());
|
||||
lv_style_set_bg_opa(&style_bar_bg, LV_OPA_COVER);
|
||||
lv_style_set_border_color(&style_bar_bg, lv_color_black());
|
||||
lv_style_set_border_width(&style_bar_bg, 1);
|
||||
lv_style_set_radius(&style_bar_bg, 0);
|
||||
|
||||
/* Bar indicator: solid black fill */
|
||||
lv_style_init(&style_bar_ind);
|
||||
lv_style_set_bg_color(&style_bar_ind, lv_color_black());
|
||||
lv_style_set_bg_opa(&style_bar_ind, LV_OPA_COVER);
|
||||
lv_style_set_radius(&style_bar_ind, 0);
|
||||
}
|
||||
|
||||
static lv_obj_t *create_bar(lv_obj_t *parent, int x, int y, int w, int h)
|
||||
{
|
||||
lv_obj_t *bar = lv_bar_create(parent);
|
||||
lv_obj_set_pos(bar, x, y);
|
||||
lv_obj_set_size(bar, w, h);
|
||||
lv_bar_set_range(bar, 0, 100);
|
||||
lv_bar_set_value(bar, 0, LV_ANIM_OFF);
|
||||
lv_obj_add_style(bar, &style_bar_bg, LV_PART_MAIN);
|
||||
lv_obj_add_style(bar, &style_bar_ind, LV_PART_INDICATOR);
|
||||
return bar;
|
||||
}
|
||||
|
||||
static lv_obj_t *create_label(lv_obj_t *parent, int x, int y, const lv_font_t *font, const char *text)
|
||||
{
|
||||
lv_obj_t *lbl = lv_label_create(parent);
|
||||
lv_obj_set_pos(lbl, x, y);
|
||||
lv_obj_set_style_text_font(lbl, font, 0);
|
||||
lv_obj_set_style_text_color(lbl, lv_color_black(), 0);
|
||||
lv_label_set_text(lbl, text);
|
||||
return lbl;
|
||||
}
|
||||
|
||||
/* ---------- Create UI ---------- */
|
||||
|
||||
static void create_top_bar(lv_obj_t *parent)
|
||||
{
|
||||
lv_obj_t *bar_cont = lv_obj_create(parent);
|
||||
lv_obj_set_pos(bar_cont, 0, 0);
|
||||
lv_obj_set_size(bar_cont, SCREEN_W, TOP_BAR_H);
|
||||
lv_obj_set_style_bg_color(bar_cont, lv_color_black(), 0);
|
||||
lv_obj_set_style_bg_opa(bar_cont, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(bar_cont, 0, 0);
|
||||
lv_obj_set_style_radius(bar_cont, 0, 0);
|
||||
lv_obj_set_style_pad_all(bar_cont, 2, 0);
|
||||
lv_obj_clear_flag(bar_cont, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lbl_ip = lv_label_create(bar_cont);
|
||||
lv_obj_set_style_text_color(lbl_ip, lv_color_white(), 0);
|
||||
lv_obj_set_style_text_font(lbl_ip, &lv_font_montserrat_12, 0);
|
||||
lv_obj_align(lbl_ip, LV_ALIGN_LEFT_MID, 2, 0);
|
||||
lv_label_set_text(lbl_ip, "N/A");
|
||||
|
||||
lbl_batt = lv_label_create(bar_cont);
|
||||
lv_obj_set_style_text_color(lbl_batt, lv_color_white(), 0);
|
||||
lv_obj_set_style_text_font(lbl_batt, &lv_font_montserrat_12, 0);
|
||||
lv_obj_align(lbl_batt, LV_ALIGN_LEFT_MID, 120, 0);
|
||||
lv_label_set_text(lbl_batt, "Batt:--%");
|
||||
|
||||
lbl_time = lv_label_create(bar_cont);
|
||||
lv_obj_set_style_text_color(lbl_time, lv_color_white(), 0);
|
||||
lv_obj_set_style_text_font(lbl_time, &lv_font_montserrat_12, 0);
|
||||
lv_obj_align(lbl_time, LV_ALIGN_LEFT_MID, 220, 0);
|
||||
lv_label_set_text(lbl_time, "--:--");
|
||||
|
||||
lbl_ws = lv_label_create(bar_cont);
|
||||
lv_obj_set_style_text_color(lbl_ws, lv_color_white(), 0);
|
||||
lv_obj_set_style_text_font(lbl_ws, &lv_font_montserrat_12, 0);
|
||||
lv_obj_align(lbl_ws, LV_ALIGN_RIGHT_MID, -2, 0);
|
||||
lv_label_set_text(lbl_ws, "WS:---");
|
||||
}
|
||||
|
||||
static void create_stats_section(lv_obj_t *parent)
|
||||
{
|
||||
int y0 = TOP_BAR_H + 2;
|
||||
int col_w = 80;
|
||||
int bar_w = 50;
|
||||
int bar_h = 40;
|
||||
|
||||
/* Section header */
|
||||
create_label(parent, 4, y0, &lv_font_montserrat_12, "PI SERVER STATS");
|
||||
|
||||
y0 += 14;
|
||||
|
||||
/* CPU */
|
||||
create_label(parent, 10, y0, &lv_font_montserrat_12, "CPU");
|
||||
bar_cpu = create_bar(parent, 10, y0 + 14, bar_w, bar_h);
|
||||
lbl_cpu_val = create_label(parent, 10, y0 + 56, &lv_font_montserrat_14, "--%");
|
||||
|
||||
/* RAM */
|
||||
create_label(parent, 10 + col_w, y0, &lv_font_montserrat_12, "RAM");
|
||||
bar_ram = create_bar(parent, 10 + col_w, y0 + 14, bar_w, bar_h);
|
||||
lbl_ram_val = create_label(parent, 10 + col_w, y0 + 56, &lv_font_montserrat_14, "--%");
|
||||
|
||||
/* DISK */
|
||||
create_label(parent, 10 + col_w * 2, y0, &lv_font_montserrat_12, "DISK");
|
||||
bar_disk = create_bar(parent, 10 + col_w * 2, y0 + 14, bar_w, bar_h);
|
||||
lbl_disk_val = create_label(parent, 10 + col_w * 2, y0 + 56, &lv_font_montserrat_14, "--%");
|
||||
|
||||
/* CPU TEMP - no bar, just big value */
|
||||
create_label(parent, 10 + col_w * 3, y0, &lv_font_montserrat_12, "TEMP");
|
||||
lbl_cpu_temp = create_label(parent, 10 + col_w * 3, y0 + 24, &lv_font_montserrat_20, "--C");
|
||||
}
|
||||
|
||||
static void create_mid_section(lv_obj_t *parent)
|
||||
{
|
||||
int y0 = TOP_BAR_H + STATS_H + 4;
|
||||
|
||||
/* --- Left column: Services --- */
|
||||
create_label(parent, 4, y0, &lv_font_montserrat_12, "SERVICES");
|
||||
|
||||
tbl_services = lv_table_create(parent);
|
||||
lv_obj_set_pos(tbl_services, 4, y0 + 14);
|
||||
lv_obj_set_size(tbl_services, 195, 110);
|
||||
lv_table_set_col_cnt(tbl_services, 2);
|
||||
lv_table_set_col_width(tbl_services, 0, 110);
|
||||
lv_table_set_col_width(tbl_services, 1, 70);
|
||||
lv_obj_set_style_text_font(tbl_services, &lv_font_montserrat_12, 0);
|
||||
lv_obj_set_style_border_color(tbl_services, lv_color_black(), 0);
|
||||
lv_obj_set_style_border_width(tbl_services, 1, 0);
|
||||
lv_obj_set_style_pad_ver(tbl_services, 2, LV_PART_ITEMS);
|
||||
lv_obj_set_style_pad_hor(tbl_services, 4, LV_PART_ITEMS);
|
||||
lv_obj_clear_flag(tbl_services, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
/* Pre-fill with empty rows */
|
||||
for (int i = 0; i < WS_MAX_SERVICES; i++) {
|
||||
lv_table_set_cell_value(tbl_services, i, 0, "---");
|
||||
lv_table_set_cell_value(tbl_services, i, 1, "---");
|
||||
}
|
||||
|
||||
/* --- Right column: Local sensors --- */
|
||||
int rx = 205;
|
||||
create_label(parent, rx, y0, &lv_font_montserrat_12, "LOCAL SENSORS");
|
||||
|
||||
lbl_room_temp = create_label(parent, rx, y0 + 18, &lv_font_montserrat_14, "Room: --.-C");
|
||||
lbl_room_humi = create_label(parent, rx, y0 + 38, &lv_font_montserrat_14, "Humi: --%");
|
||||
lbl_local_batt = create_label(parent, rx, y0 + 58, &lv_font_montserrat_14, "Batt: --%");
|
||||
lbl_uptime = create_label(parent, rx, y0 + 78, &lv_font_montserrat_14, "Uptime: --h");
|
||||
}
|
||||
|
||||
static void create_bottom_bar(lv_obj_t *parent)
|
||||
{
|
||||
int y0 = SCREEN_H - BOT_H;
|
||||
|
||||
lv_obj_t *bot_cont = lv_obj_create(parent);
|
||||
lv_obj_set_pos(bot_cont, 0, y0);
|
||||
lv_obj_set_size(bot_cont, SCREEN_W, BOT_H);
|
||||
lv_obj_set_style_bg_color(bot_cont, lv_color_white(), 0);
|
||||
lv_obj_set_style_bg_opa(bot_cont, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_color(bot_cont, lv_color_black(), 0);
|
||||
lv_obj_set_style_border_width(bot_cont, 1, 0);
|
||||
lv_obj_set_style_border_side(bot_cont, LV_BORDER_SIDE_TOP, 0);
|
||||
lv_obj_set_style_radius(bot_cont, 0, 0);
|
||||
lv_obj_set_style_pad_all(bot_cont, 4, 0);
|
||||
lv_obj_clear_flag(bot_cont, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lbl_net = lv_label_create(bot_cont);
|
||||
lv_obj_set_style_text_font(lbl_net, &lv_font_montserrat_12, 0);
|
||||
lv_obj_set_style_text_color(lbl_net, lv_color_black(), 0);
|
||||
lv_obj_align(lbl_net, LV_ALIGN_LEFT_MID, 0, 0);
|
||||
lv_label_set_text(lbl_net, "NETWORK RX: ---- kbps TX: ---- kbps");
|
||||
}
|
||||
|
||||
void dashboard_ui_create(void)
|
||||
{
|
||||
init_styles();
|
||||
|
||||
lv_obj_t *scr = lv_scr_act();
|
||||
lv_obj_set_style_bg_color(scr, lv_color_white(), 0);
|
||||
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
|
||||
lv_obj_clear_flag(scr, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
create_top_bar(scr);
|
||||
create_stats_section(scr);
|
||||
create_mid_section(scr);
|
||||
create_bottom_bar(scr);
|
||||
}
|
||||
|
||||
/* ---------- Update functions ---------- */
|
||||
|
||||
void dashboard_ui_update_stats(const pi_stats_t *stats)
|
||||
{
|
||||
if (!stats || !stats->valid) return;
|
||||
|
||||
char buf[32];
|
||||
|
||||
/* Bars */
|
||||
lv_bar_set_value(bar_cpu, (int)stats->cpu_pct, LV_ANIM_OFF);
|
||||
snprintf(buf, sizeof(buf), "%d%%", (int)stats->cpu_pct);
|
||||
lv_label_set_text(lbl_cpu_val, buf);
|
||||
|
||||
lv_bar_set_value(bar_ram, (int)stats->mem_pct, LV_ANIM_OFF);
|
||||
snprintf(buf, sizeof(buf), "%d%%", (int)stats->mem_pct);
|
||||
lv_label_set_text(lbl_ram_val, buf);
|
||||
|
||||
lv_bar_set_value(bar_disk, (int)stats->disk_pct, LV_ANIM_OFF);
|
||||
snprintf(buf, sizeof(buf), "%d%%", (int)stats->disk_pct);
|
||||
lv_label_set_text(lbl_disk_val, buf);
|
||||
|
||||
/* CPU temp */
|
||||
snprintf(buf, sizeof(buf), "%.0fC", stats->cpu_temp);
|
||||
lv_label_set_text(lbl_cpu_temp, buf);
|
||||
|
||||
/* Services table */
|
||||
for (int i = 0; i < stats->service_count && i < WS_MAX_SERVICES; i++) {
|
||||
lv_table_set_cell_value(tbl_services, i, 0, stats->services[i].name);
|
||||
lv_table_set_cell_value(tbl_services, i, 1,
|
||||
stats->services[i].running ? "[RUN]" : "[STOP]");
|
||||
}
|
||||
/* Clear unused rows */
|
||||
for (int i = stats->service_count; i < WS_MAX_SERVICES; i++) {
|
||||
lv_table_set_cell_value(tbl_services, i, 0, "");
|
||||
lv_table_set_cell_value(tbl_services, i, 1, "");
|
||||
}
|
||||
|
||||
/* Uptime */
|
||||
snprintf(buf, sizeof(buf), "Uptime: %.0fh", stats->uptime_hrs);
|
||||
lv_label_set_text(lbl_uptime, buf);
|
||||
|
||||
/* Network */
|
||||
char net_buf[64];
|
||||
snprintf(net_buf, sizeof(net_buf), "NETWORK RX: %.0f kbps TX: %.0f kbps",
|
||||
stats->net_rx_kbps, stats->net_tx_kbps);
|
||||
lv_label_set_text(lbl_net, net_buf);
|
||||
}
|
||||
|
||||
void dashboard_ui_update_local(float temp, float humidity, uint8_t battery)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Room: %.1fC", temp);
|
||||
lv_label_set_text(lbl_room_temp, buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "Humi: %.0f%%", humidity);
|
||||
lv_label_set_text(lbl_room_humi, buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "Batt: %d%%", battery);
|
||||
lv_label_set_text(lbl_local_batt, buf);
|
||||
|
||||
/* Also update top bar battery */
|
||||
snprintf(buf, sizeof(buf), "Batt:%d%%", battery);
|
||||
lv_label_set_text(lbl_batt, buf);
|
||||
}
|
||||
|
||||
void dashboard_ui_update_time(int h, int m, int s)
|
||||
{
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%02d:%02d", h, m);
|
||||
lv_label_set_text(lbl_time, buf);
|
||||
}
|
||||
|
||||
void dashboard_ui_update_connection(ws_state_t ws_state, bool wifi_connected, const char *ip_str)
|
||||
{
|
||||
/* IP / WiFi status */
|
||||
lv_label_set_text(lbl_ip, ip_str ? ip_str : "N/A");
|
||||
|
||||
/* WS status */
|
||||
const char *ws_str;
|
||||
switch (ws_state) {
|
||||
case WS_STATE_CONNECTED: ws_str = "WS:LIVE"; break;
|
||||
case WS_STATE_CONNECTING: ws_str = "WS:..."; break;
|
||||
case WS_STATE_DISCONNECTED: ws_str = "WS:OFF"; break;
|
||||
case WS_STATE_ERROR: ws_str = "WS:ERR"; break;
|
||||
default: ws_str = "WS:---"; break;
|
||||
}
|
||||
lv_label_set_text(lbl_ws, ws_str);
|
||||
}
|
||||
41
components/dashboard_ui/dashboard_ui.h
Normal file
41
components/dashboard_ui/dashboard_ui.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef DASHBOARD_UI_H
|
||||
#define DASHBOARD_UI_H
|
||||
|
||||
#include "ws_client.h"
|
||||
#include "lvgl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create the full dashboard UI. Must be called with LVGL lock held.
|
||||
*/
|
||||
void dashboard_ui_create(void);
|
||||
|
||||
/**
|
||||
* Update Pi server stats display. LVGL lock must be held by caller.
|
||||
*/
|
||||
void dashboard_ui_update_stats(const pi_stats_t *stats);
|
||||
|
||||
/**
|
||||
* Update local sensor readings. LVGL lock must be held by caller.
|
||||
*/
|
||||
void dashboard_ui_update_local(float temp, float humidity, uint8_t battery);
|
||||
|
||||
/**
|
||||
* Update time display. LVGL lock must be held by caller.
|
||||
*/
|
||||
void dashboard_ui_update_time(int h, int m, int s);
|
||||
|
||||
/**
|
||||
* Update connection status indicators. LVGL lock must be held by caller.
|
||||
* ip_str: IP address string when connected, "Connecting..." during reconnect, "N/A" when disconnected
|
||||
*/
|
||||
void dashboard_ui_update_connection(ws_state_t ws_state, bool wifi_connected, const char *ip_str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user