dashboard: render battery soc gauge
This commit is contained in:
@@ -14,9 +14,11 @@ using namespace esp_panel::board;
|
||||
|
||||
static DashboardStatus status_model;
|
||||
|
||||
static lv_obj_t *soc_value_label = nullptr;
|
||||
static lv_obj_t *battery_soc_arc = nullptr;
|
||||
static lv_obj_t *battery_charge_pulse_arc = nullptr;
|
||||
static lv_obj_t *battery_voltage_label = nullptr;
|
||||
static lv_obj_t *battery_current_label = nullptr;
|
||||
static lv_obj_t *battery_soc_label = nullptr;
|
||||
static lv_obj_t *battery_capacity_label = nullptr;
|
||||
static lv_obj_t *battery_health_label = nullptr;
|
||||
static lv_obj_t *inside_temp_label = nullptr;
|
||||
@@ -44,9 +46,9 @@ static bool pending_relay_state = false;
|
||||
static int pending_relay_index = -1;
|
||||
static bool pending_relay_previous_state = false;
|
||||
|
||||
static String last_soc_text;
|
||||
static String last_battery_voltage_text;
|
||||
static String last_battery_current_text;
|
||||
static String last_battery_soc_text;
|
||||
static String last_battery_capacity_text;
|
||||
static String last_battery_health_text;
|
||||
static String last_inside_temp_text;
|
||||
@@ -58,6 +60,93 @@ static String on_off(bool value)
|
||||
return value ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
static int clamp_int(int value, int min_value, int max_value)
|
||||
{
|
||||
if (value < min_value) {
|
||||
return min_value;
|
||||
}
|
||||
|
||||
if (value > max_value) {
|
||||
return max_value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void update_battery_current_label(const String &text, float current)
|
||||
{
|
||||
if (battery_current_label == nullptr || last_battery_current_text == text) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_battery_current_text = text;
|
||||
|
||||
lv_color_t current_color = lv_color_hex(0xB8C0C8);
|
||||
if (current > 0.05) {
|
||||
current_color = lv_color_hex(0x32D583);
|
||||
} else if (current < -0.05) {
|
||||
current_color = lv_color_hex(0xF97066);
|
||||
}
|
||||
|
||||
lvgl_port_lock(-1);
|
||||
|
||||
if (text.length() == 0) {
|
||||
lv_obj_add_flag(battery_current_label, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_obj_clear_flag(battery_current_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_label_set_text(battery_current_label, text.c_str());
|
||||
lv_obj_set_style_text_color(battery_current_label, current_color, 0);
|
||||
}
|
||||
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
static void update_battery_soc_gauge()
|
||||
{
|
||||
if (battery_soc_arc == nullptr || battery_charge_pulse_arc == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
int soc = clamp_int(status_model.soc, 0, 100);
|
||||
bool charging = status_model.current > 0.05;
|
||||
|
||||
lvgl_port_lock(-1);
|
||||
|
||||
lv_arc_set_value(battery_soc_arc, soc);
|
||||
lv_arc_set_value(battery_charge_pulse_arc, soc);
|
||||
|
||||
if (charging) {
|
||||
lv_obj_clear_flag(battery_charge_pulse_arc, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_obj_add_flag(battery_charge_pulse_arc, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
static void update_battery_charge_animation()
|
||||
{
|
||||
if (battery_charge_pulse_arc == nullptr || status_model.current <= 0.05) {
|
||||
return;
|
||||
}
|
||||
|
||||
static unsigned long last_pulse_ms = 0;
|
||||
static bool pulse_high = false;
|
||||
|
||||
if (millis() - last_pulse_ms < 450) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_pulse_ms = millis();
|
||||
pulse_high = !pulse_high;
|
||||
|
||||
lvgl_port_lock(-1);
|
||||
lv_obj_set_style_arc_width(battery_charge_pulse_arc, pulse_high ? 20 : 12, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_opa(battery_charge_pulse_arc, pulse_high ? LV_OPA_80 : LV_OPA_35, LV_PART_INDICATOR);
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
|
||||
static void set_label_text_if_changed(lv_obj_t *label, String &last_text, const String &text)
|
||||
{
|
||||
if (label == nullptr || last_text == text) {
|
||||
@@ -257,17 +346,20 @@ static void update_system_status_label()
|
||||
|
||||
static void update_overview_widgets()
|
||||
{
|
||||
String soc_text;
|
||||
soc_text += status_model.soc >= 0 ? String(status_model.soc) : "--";
|
||||
soc_text += "%";
|
||||
|
||||
String voltage_text;
|
||||
voltage_text += String(status_model.voltage, 2);
|
||||
voltage_text += " V";
|
||||
|
||||
String current_text;
|
||||
current_text += String(status_model.current, 2);
|
||||
current_text += " A";
|
||||
String current_text = "";
|
||||
if (status_model.current > 0.05 || status_model.current < -0.05) {
|
||||
current_text += status_model.current > 0 ? "+" : "";
|
||||
current_text += String(status_model.current, 2);
|
||||
current_text += " A";
|
||||
}
|
||||
|
||||
String soc_text;
|
||||
soc_text += status_model.soc >= 0 ? String(status_model.soc) : "--";
|
||||
soc_text += "% SOC";
|
||||
|
||||
String capacity_text;
|
||||
capacity_text += String(status_model.remaining_ah, 1);
|
||||
@@ -287,9 +379,10 @@ static void update_overview_widgets()
|
||||
health_text += " mV";
|
||||
}
|
||||
|
||||
set_label_text_if_changed(soc_value_label, last_soc_text, soc_text);
|
||||
update_battery_soc_gauge();
|
||||
set_label_text_if_changed(battery_voltage_label, last_battery_voltage_text, voltage_text);
|
||||
set_label_text_if_changed(battery_current_label, last_battery_current_text, current_text);
|
||||
update_battery_current_label(current_text, status_model.current);
|
||||
set_label_text_if_changed(battery_soc_label, last_battery_soc_text, soc_text);
|
||||
set_label_text_if_changed(battery_capacity_label, last_battery_capacity_text, capacity_text);
|
||||
set_label_text_if_changed(battery_health_label, last_battery_health_text, health_text);
|
||||
set_label_text_if_changed(system_status_label, last_system_status_text, last_system_status_text);
|
||||
@@ -485,39 +578,72 @@ static void create_overland_overview_screen()
|
||||
lv_obj_t *relay_card = create_card(screen, "Outputs", 300, 255, LV_ALIGN_TOP_RIGHT, -32, 80);
|
||||
lv_obj_t *system_card = create_card(screen, "System", 620, 175, LV_ALIGN_BOTTOM_LEFT, 32, -50);
|
||||
|
||||
soc_value_label = lv_label_create(battery_card);
|
||||
lv_label_set_text(soc_value_label, "--%");
|
||||
lv_obj_set_style_text_color(soc_value_label, lv_color_hex(0xFFFFFF), 0);
|
||||
lv_obj_set_style_text_font(soc_value_label, &lv_font_montserrat_30, 0);
|
||||
lv_obj_align(soc_value_label, LV_ALIGN_TOP_LEFT, 0, 34);
|
||||
battery_charge_pulse_arc = lv_arc_create(battery_card);
|
||||
lv_obj_set_size(battery_charge_pulse_arc, 172, 172);
|
||||
lv_obj_align(battery_charge_pulse_arc, LV_ALIGN_TOP_MID, 0, 30);
|
||||
lv_arc_set_range(battery_charge_pulse_arc, 0, 100);
|
||||
lv_arc_set_value(battery_charge_pulse_arc, 0);
|
||||
lv_arc_set_rotation(battery_charge_pulse_arc, 135);
|
||||
lv_arc_set_bg_angles(battery_charge_pulse_arc, 0, 270);
|
||||
lv_obj_remove_style(battery_charge_pulse_arc, NULL, LV_PART_KNOB);
|
||||
lv_obj_clear_flag(battery_charge_pulse_arc, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_set_style_arc_opa(battery_charge_pulse_arc, LV_OPA_TRANSP, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_color(battery_charge_pulse_arc, lv_color_hex(0x32D583), LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_width(battery_charge_pulse_arc, 14, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_opa(battery_charge_pulse_arc, LV_OPA_35, LV_PART_INDICATOR);
|
||||
lv_obj_add_flag(battery_charge_pulse_arc, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
lv_obj_t *soc_caption = lv_label_create(battery_card);
|
||||
lv_label_set_text(soc_caption, "STATE OF CHARGE");
|
||||
lv_obj_set_style_text_color(soc_caption, lv_color_hex(0x7D8996), 0);
|
||||
lv_obj_align(soc_caption, LV_ALIGN_TOP_LEFT, 0, 82);
|
||||
battery_soc_arc = lv_arc_create(battery_card);
|
||||
lv_obj_set_size(battery_soc_arc, 158, 158);
|
||||
lv_obj_align(battery_soc_arc, LV_ALIGN_TOP_MID, 0, 37);
|
||||
lv_arc_set_range(battery_soc_arc, 0, 100);
|
||||
lv_arc_set_value(battery_soc_arc, 0);
|
||||
lv_arc_set_rotation(battery_soc_arc, 135);
|
||||
lv_arc_set_bg_angles(battery_soc_arc, 0, 270);
|
||||
lv_obj_remove_style(battery_soc_arc, NULL, LV_PART_KNOB);
|
||||
lv_obj_clear_flag(battery_soc_arc, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_set_style_arc_color(battery_soc_arc, lv_color_hex(0x3A4652), LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_width(battery_soc_arc, 13, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_color(battery_soc_arc, lv_color_hex(0x84CAFF), LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_width(battery_soc_arc, 13, LV_PART_INDICATOR);
|
||||
|
||||
battery_voltage_label = lv_label_create(battery_card);
|
||||
lv_label_set_text(battery_voltage_label, "-- V");
|
||||
lv_obj_set_style_text_color(battery_voltage_label, lv_color_hex(0xFFFFFF), 0);
|
||||
lv_obj_align(battery_voltage_label, LV_ALIGN_TOP_LEFT, 0, 112);
|
||||
lv_obj_set_style_text_font(battery_voltage_label, &lv_font_montserrat_30, 0);
|
||||
lv_obj_set_width(battery_voltage_label, 180);
|
||||
lv_obj_set_style_text_align(battery_voltage_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_align(battery_voltage_label, LV_ALIGN_TOP_MID, 0, 83);
|
||||
|
||||
battery_current_label = lv_label_create(battery_card);
|
||||
lv_label_set_text(battery_current_label, "-- A");
|
||||
lv_obj_set_style_text_color(battery_current_label, lv_color_hex(0xFFFFFF), 0);
|
||||
lv_obj_align(battery_current_label, LV_ALIGN_TOP_LEFT, 135, 112);
|
||||
lv_label_set_text(battery_current_label, "");
|
||||
lv_obj_set_style_text_color(battery_current_label, lv_color_hex(0xB8C0C8), 0);
|
||||
lv_obj_set_width(battery_current_label, 170);
|
||||
lv_obj_set_style_text_align(battery_current_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_align(battery_current_label, LV_ALIGN_TOP_MID, 0, 122);
|
||||
lv_obj_add_flag(battery_current_label, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
battery_soc_label = lv_label_create(battery_card);
|
||||
lv_label_set_text(battery_soc_label, "--% SOC");
|
||||
lv_obj_set_style_text_color(battery_soc_label, lv_color_hex(0xB8C0C8), 0);
|
||||
lv_obj_set_width(battery_soc_label, 180);
|
||||
lv_obj_set_style_text_align(battery_soc_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_align(battery_soc_label, LV_ALIGN_TOP_MID, 0, 155);
|
||||
|
||||
battery_capacity_label = lv_label_create(battery_card);
|
||||
lv_label_set_text(battery_capacity_label, "-- / -- Ah");
|
||||
lv_obj_set_style_text_color(battery_capacity_label, lv_color_hex(0xDDE3EA), 0);
|
||||
lv_obj_set_width(battery_capacity_label, 260);
|
||||
lv_obj_align(battery_capacity_label, LV_ALIGN_TOP_LEFT, 0, 148);
|
||||
lv_obj_set_style_text_align(battery_capacity_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_align(battery_capacity_label, LV_ALIGN_TOP_MID, 0, 190);
|
||||
|
||||
battery_health_label = lv_label_create(battery_card);
|
||||
lv_label_set_text(battery_health_label, "Waiting for BMS...");
|
||||
lv_obj_set_style_text_color(battery_health_label, lv_color_hex(0xB8C0C8), 0);
|
||||
lv_obj_set_width(battery_health_label, 260);
|
||||
lv_label_set_long_mode(battery_health_label, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_align(battery_health_label, LV_ALIGN_TOP_LEFT, 0, 182);
|
||||
lv_obj_set_style_text_align(battery_health_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_align(battery_health_label, LV_ALIGN_TOP_MID, 0, 214);
|
||||
|
||||
inside_temp_label = lv_label_create(temp_card);
|
||||
lv_label_set_text(inside_temp_label, "Inside\n--");
|
||||
@@ -612,6 +738,7 @@ void loop()
|
||||
update_system_status_label();
|
||||
process_pending_relay_command();
|
||||
poll_status_api();
|
||||
update_battery_charge_animation();
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user