|
|
|
@@ -40,6 +40,13 @@ static lv_obj_t *vehicle_fuel_value_label = nullptr;
|
|
|
|
|
static lv_obj_t *relay_buttons[6] = {nullptr};
|
|
|
|
|
static lv_obj_t *relay_button_labels[6] = {nullptr};
|
|
|
|
|
|
|
|
|
|
static lv_obj_t *diagnostics_overlay = nullptr;
|
|
|
|
|
static lv_obj_t *diagnostics_label = nullptr;
|
|
|
|
|
static unsigned long diagnostics_last_update_ms = 0;
|
|
|
|
|
static unsigned long diagnostics_last_tap_ms = 0;
|
|
|
|
|
static unsigned long system_card_last_tap_ms = 0;
|
|
|
|
|
static int system_card_tap_count = 0;
|
|
|
|
|
|
|
|
|
|
static String relay_ids[6];
|
|
|
|
|
static String relay_names[6];
|
|
|
|
|
static bool relay_states[6] = {false};
|
|
|
|
@@ -353,8 +360,200 @@ static void request_fast_status_refresh()
|
|
|
|
|
fast_status_refresh_requested = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static String format_diag_uptime(unsigned long seconds)
|
|
|
|
|
{
|
|
|
|
|
unsigned long days = seconds / 86400;
|
|
|
|
|
seconds %= 86400;
|
|
|
|
|
unsigned long hours = seconds / 3600;
|
|
|
|
|
seconds %= 3600;
|
|
|
|
|
unsigned long minutes = seconds / 60;
|
|
|
|
|
|
|
|
|
|
String out;
|
|
|
|
|
if (days > 0) {
|
|
|
|
|
out += String(days);
|
|
|
|
|
out += "d ";
|
|
|
|
|
}
|
|
|
|
|
out += String(hours);
|
|
|
|
|
out += "h ";
|
|
|
|
|
out += String(minutes);
|
|
|
|
|
out += "m";
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void update_diagnostics_overlay()
|
|
|
|
|
{
|
|
|
|
|
if (diagnostics_overlay == nullptr || diagnostics_label == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (millis() - diagnostics_last_update_ms < 500) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diagnostics_last_update_ms = millis();
|
|
|
|
|
|
|
|
|
|
String text;
|
|
|
|
|
text += "DIAGNOSTICS\n\n";
|
|
|
|
|
|
|
|
|
|
text += "Dashboard ESP32-S3\n";
|
|
|
|
|
text += " Version: ";
|
|
|
|
|
text += DASHBOARD_VERSION;
|
|
|
|
|
text += "\n Uptime: ";
|
|
|
|
|
text += format_diag_uptime(millis() / 1000);
|
|
|
|
|
text += "\n Free heap: ";
|
|
|
|
|
text += String(ESP.getFreeHeap());
|
|
|
|
|
text += "\n Min heap: ";
|
|
|
|
|
text += String(ESP.getMinFreeHeap());
|
|
|
|
|
text += "\n WiFi: ";
|
|
|
|
|
text += WiFi.status() == WL_CONNECTED ? "connected" : "offline";
|
|
|
|
|
text += "\n RSSI: ";
|
|
|
|
|
text += WiFi.status() == WL_CONNECTED ? String(WiFi.RSSI()) : String("--");
|
|
|
|
|
text += " dBm\n IP: ";
|
|
|
|
|
text += WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : String("--");
|
|
|
|
|
text += "\n Last HTTP: ";
|
|
|
|
|
text += String(status_model.http_code);
|
|
|
|
|
text += "\n Cargo API: ";
|
|
|
|
|
text += status_model.api_ok ? "OK" : "FAIL";
|
|
|
|
|
|
|
|
|
|
text += "\n\nCargo ESP\n";
|
|
|
|
|
text += " Version: ";
|
|
|
|
|
text += status_model.firmware_version;
|
|
|
|
|
text += "\n Uptime: ";
|
|
|
|
|
text += format_diag_uptime(status_model.uptime_seconds);
|
|
|
|
|
text += "\n Chip: ";
|
|
|
|
|
text += status_model.cargo_chip_model;
|
|
|
|
|
text += "\n CPU: ";
|
|
|
|
|
text += String(status_model.cargo_cpu_mhz);
|
|
|
|
|
text += " MHz";
|
|
|
|
|
text += "\n Free heap: ";
|
|
|
|
|
text += String(status_model.cargo_free_heap);
|
|
|
|
|
text += "\n Min heap: ";
|
|
|
|
|
text += String(status_model.cargo_min_free_heap);
|
|
|
|
|
|
|
|
|
|
text += "\n\nCargo Network\n";
|
|
|
|
|
text += " AP SSID: ";
|
|
|
|
|
text += status_model.cargo_ap_ssid;
|
|
|
|
|
text += "\n AP clients: ";
|
|
|
|
|
text += String(status_model.cargo_ap_clients);
|
|
|
|
|
text += "\n STA IP: ";
|
|
|
|
|
text += status_model.cargo_sta_ip.length() ? status_model.cargo_sta_ip : String("--");
|
|
|
|
|
text += "\n STA RSSI: ";
|
|
|
|
|
text += status_model.cargo_sta_rssi_dbm == 0 ? String("--") : String(status_model.cargo_sta_rssi_dbm);
|
|
|
|
|
text += " dBm";
|
|
|
|
|
|
|
|
|
|
text += "\n\nPower / Sensors\n";
|
|
|
|
|
text += " BMS: ";
|
|
|
|
|
text += status_model.bms_connected ? "connected" : "offline";
|
|
|
|
|
text += "\n SOC: ";
|
|
|
|
|
text += status_model.soc >= 0 ? String(status_model.soc) + "%" : String("--");
|
|
|
|
|
text += "\n Current: ";
|
|
|
|
|
text += String(status_model.current, 2);
|
|
|
|
|
text += " A";
|
|
|
|
|
text += "\n Cell delta: ";
|
|
|
|
|
text += String(status_model.cell_delta_mv);
|
|
|
|
|
text += " mV";
|
|
|
|
|
|
|
|
|
|
text += "\n\nControls\n";
|
|
|
|
|
text += " Relays visible: ";
|
|
|
|
|
text += String(relay_count);
|
|
|
|
|
text += "\n API busy: ";
|
|
|
|
|
text += api_request_in_progress ? "yes" : "no";
|
|
|
|
|
|
|
|
|
|
text += "\n\nDouble tap anywhere to return.";
|
|
|
|
|
|
|
|
|
|
lvgl_port_lock(-1);
|
|
|
|
|
lv_label_set_text(diagnostics_label, text.c_str());
|
|
|
|
|
lvgl_port_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void close_diagnostics_overlay()
|
|
|
|
|
{
|
|
|
|
|
if (diagnostics_overlay == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lvgl_port_lock(-1);
|
|
|
|
|
lv_obj_del(diagnostics_overlay);
|
|
|
|
|
diagnostics_overlay = nullptr;
|
|
|
|
|
diagnostics_label = nullptr;
|
|
|
|
|
lvgl_port_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void diagnostics_overlay_event_cb(lv_event_t *event)
|
|
|
|
|
{
|
|
|
|
|
if (lv_event_get_code(event) != LV_EVENT_CLICKED) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned long now = millis();
|
|
|
|
|
if (now - diagnostics_last_tap_ms < 650) {
|
|
|
|
|
close_diagnostics_overlay();
|
|
|
|
|
diagnostics_last_tap_ms = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diagnostics_last_tap_ms = now;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void show_diagnostics_overlay()
|
|
|
|
|
{
|
|
|
|
|
if (diagnostics_overlay != nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lvgl_port_lock(-1);
|
|
|
|
|
|
|
|
|
|
diagnostics_overlay = lv_obj_create(lv_scr_act());
|
|
|
|
|
lv_obj_set_size(diagnostics_overlay, 1024, 600);
|
|
|
|
|
lv_obj_align(diagnostics_overlay, LV_ALIGN_CENTER, 0, 0);
|
|
|
|
|
lv_obj_set_style_bg_color(diagnostics_overlay, lv_color_hex(0x101418), 0);
|
|
|
|
|
lv_obj_set_style_bg_opa(diagnostics_overlay, LV_OPA_COVER, 0);
|
|
|
|
|
lv_obj_set_style_border_width(diagnostics_overlay, 0, 0);
|
|
|
|
|
lv_obj_set_style_pad_all(diagnostics_overlay, 22, 0);
|
|
|
|
|
lv_obj_add_flag(diagnostics_overlay, LV_OBJ_FLAG_CLICKABLE);
|
|
|
|
|
lv_obj_add_event_cb(diagnostics_overlay, diagnostics_overlay_event_cb, LV_EVENT_CLICKED, nullptr);
|
|
|
|
|
|
|
|
|
|
diagnostics_label = lv_label_create(diagnostics_overlay);
|
|
|
|
|
lv_label_set_text(diagnostics_label, "DIAGNOSTICS\nLoading...");
|
|
|
|
|
lv_obj_set_style_text_color(diagnostics_label, lv_color_hex(0xDDE3EA), 0);
|
|
|
|
|
lv_obj_set_style_text_font(diagnostics_label, &lv_font_montserrat_26, 0);
|
|
|
|
|
lv_obj_set_width(diagnostics_label, 960);
|
|
|
|
|
lv_label_set_long_mode(diagnostics_label, LV_LABEL_LONG_WRAP);
|
|
|
|
|
lv_obj_align(diagnostics_label, LV_ALIGN_TOP_LEFT, 8, 8);
|
|
|
|
|
|
|
|
|
|
lvgl_port_unlock();
|
|
|
|
|
|
|
|
|
|
diagnostics_last_update_ms = 0;
|
|
|
|
|
update_diagnostics_overlay();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void system_card_event_cb(lv_event_t *event)
|
|
|
|
|
{
|
|
|
|
|
if (lv_event_get_code(event) != LV_EVENT_CLICKED) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned long now = millis();
|
|
|
|
|
if (now - system_card_last_tap_ms > 3000) {
|
|
|
|
|
system_card_tap_count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
system_card_last_tap_ms = now;
|
|
|
|
|
system_card_tap_count++;
|
|
|
|
|
|
|
|
|
|
if (system_card_tap_count >= 5) {
|
|
|
|
|
system_card_tap_count = 0;
|
|
|
|
|
show_diagnostics_overlay();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void create_overland_overview_screen();
|
|
|
|
|
static void show_boot_screen();
|
|
|
|
|
static void show_diagnostics_overlay();
|
|
|
|
|
static void close_diagnostics_overlay();
|
|
|
|
|
static void update_diagnostics_overlay();
|
|
|
|
|
|
|
|
|
|
static void layout_relay_buttons()
|
|
|
|
|
{
|
|
|
|
@@ -903,12 +1102,18 @@ static void parse_status_json(const String &body)
|
|
|
|
|
JsonObject system = doc["system"];
|
|
|
|
|
status_model.firmware_version = String((const char *)(system["firmware_version"] | status_model.firmware_version.c_str()));
|
|
|
|
|
status_model.uptime_seconds = system["uptime_seconds"] | status_model.uptime_seconds;
|
|
|
|
|
status_model.cargo_free_heap = system["free_heap"] | status_model.cargo_free_heap;
|
|
|
|
|
status_model.cargo_min_free_heap = system["min_free_heap"] | status_model.cargo_min_free_heap;
|
|
|
|
|
status_model.cargo_chip_model = String((const char *)(system["chip_model"] | status_model.cargo_chip_model.c_str()));
|
|
|
|
|
status_model.cargo_cpu_mhz = system["cpu_mhz"] | status_model.cargo_cpu_mhz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doc["network"].is<JsonObject>()) {
|
|
|
|
|
JsonObject network = doc["network"];
|
|
|
|
|
status_model.cargo_ap_ssid = String((const char *)(network["ap_ssid"] | status_model.cargo_ap_ssid.c_str()));
|
|
|
|
|
status_model.cargo_sta_ip = String((const char *)(network["sta_ip"] | status_model.cargo_sta_ip.c_str()));
|
|
|
|
|
status_model.cargo_ap_clients = network["ap_clients"] | status_model.cargo_ap_clients;
|
|
|
|
|
status_model.cargo_sta_rssi_dbm = network["sta_rssi_dbm"] | status_model.cargo_sta_rssi_dbm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doc["temps"].is<JsonArray>()) {
|
|
|
|
@@ -1188,6 +1393,8 @@ static void create_overland_overview_screen()
|
|
|
|
|
lv_obj_set_style_bg_color(screen, lv_color_hex(0x101418), 0);
|
|
|
|
|
|
|
|
|
|
lv_obj_t *system_card = create_card(screen, "", 960, 48, LV_ALIGN_TOP_MID, 0, 12);
|
|
|
|
|
lv_obj_add_flag(system_card, LV_OBJ_FLAG_CLICKABLE);
|
|
|
|
|
lv_obj_add_event_cb(system_card, system_card_event_cb, LV_EVENT_CLICKED, nullptr);
|
|
|
|
|
lv_obj_t *battery_card = create_card(screen, "", 380, 310, LV_ALIGN_TOP_LEFT, 32, 68);
|
|
|
|
|
battery_card_obj = battery_card;
|
|
|
|
|
lv_obj_t *temp_card = create_card(screen, "", 260, 310, LV_ALIGN_TOP_LEFT, 426, 68);
|
|
|
|
|