dashboard: use status field filtering
This commit is contained in:
@@ -65,3 +65,13 @@ Current dashboard firmware files:
|
||||
- `esp_panel_board_custom_conf.h` - Waveshare board/display configuration
|
||||
|
||||
This refactor keeps behavior unchanged while preparing for later `api` and `ui` file splits.
|
||||
|
||||
|
||||
## Status Field Filtering
|
||||
|
||||
The dashboard uses field-filtered `/api/v1/status` calls:
|
||||
|
||||
- Fast poll: `/api/v1/status?fields=battery,temps,relays`
|
||||
- Slow poll: `/api/v1/status?fields=network,system,config`
|
||||
|
||||
This keeps the endpoint model simple while reducing payload size, JSON parsing, and UI churn.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
static const char *DASHBOARD_VERSION = "0.0.8-refactor-config-model";
|
||||
static const char *DASHBOARD_VERSION = "0.0.9-status-fields";
|
||||
|
||||
// Update these if your Cargo ESP AP credentials are different.
|
||||
static const char *CARGO_WIFI_SSID = "OverlandController";
|
||||
static const char *CARGO_WIFI_PASSWORD = "overland1234";
|
||||
|
||||
static const char *CARGO_API_STATUS_URL = "http://192.168.4.1/api/v1/status";
|
||||
static const char *CARGO_API_FAST_STATUS_URL = "http://192.168.4.1/api/v1/status?fields=battery,temps,relays";
|
||||
static const char *CARGO_API_SLOW_STATUS_URL = "http://192.168.4.1/api/v1/status?fields=network,system,config";
|
||||
static const char *CARGO_API_RELAY_SET_URL = "http://192.168.4.1/api/v1/relay/set";
|
||||
|
||||
@@ -29,6 +29,7 @@ static uint32_t touch_count = 0;
|
||||
static unsigned long last_wifi_attempt_ms = 0;
|
||||
static unsigned long last_wifi_label_update_ms = 0;
|
||||
static unsigned long last_status_poll_ms = 0;
|
||||
static unsigned long last_metadata_poll_ms = 0;
|
||||
|
||||
static String last_battery_text;
|
||||
static String last_temps_text;
|
||||
@@ -264,33 +265,42 @@ static void parse_status_json(const String &body)
|
||||
status_model.api_ok = true;
|
||||
status_model.http_code = 200;
|
||||
|
||||
JsonObject battery = doc["battery"];
|
||||
status_model.bms_connected = battery["connected"] | false;
|
||||
status_model.soc = battery["soc"] | -1;
|
||||
status_model.voltage = battery["voltage"] | 0.0;
|
||||
status_model.current = battery["current"] | 0.0;
|
||||
status_model.battery_temp_f = battery["temperature_f"] | 0.0;
|
||||
status_model.remaining_ah = battery["remaining_ah"] | 0.0;
|
||||
status_model.capacity_ah = battery["capacity_ah"] | 0.0;
|
||||
status_model.cell_delta_mv = battery["cell_delta_mv"] | -1;
|
||||
if (doc["battery"].is<JsonObject>()) {
|
||||
JsonObject battery = doc["battery"];
|
||||
status_model.bms_connected = battery["connected"] | status_model.bms_connected;
|
||||
status_model.soc = battery["soc"] | status_model.soc;
|
||||
status_model.voltage = battery["voltage"] | status_model.voltage;
|
||||
status_model.current = battery["current"] | status_model.current;
|
||||
status_model.battery_temp_f = battery["temperature_f"] | status_model.battery_temp_f;
|
||||
status_model.remaining_ah = battery["remaining_ah"] | status_model.remaining_ah;
|
||||
status_model.capacity_ah = battery["capacity_ah"] | status_model.capacity_ah;
|
||||
status_model.cell_delta_mv = battery["cell_delta_mv"] | status_model.cell_delta_mv;
|
||||
}
|
||||
|
||||
JsonObject config = doc["config"];
|
||||
status_model.hardware_profile = String((const char *)(config["hardware_profile"] | "unknown"));
|
||||
status_model.output_count = config["output_count"] | 0;
|
||||
if (doc["config"].is<JsonObject>()) {
|
||||
JsonObject config = doc["config"];
|
||||
status_model.hardware_profile = String((const char *)(config["hardware_profile"] | status_model.hardware_profile.c_str()));
|
||||
status_model.output_count = config["output_count"] | status_model.output_count;
|
||||
}
|
||||
|
||||
JsonObject system = doc["system"];
|
||||
status_model.firmware_version = String((const char *)(system["firmware_version"] | "unknown"));
|
||||
status_model.uptime_seconds = system["uptime_seconds"] | 0;
|
||||
if (doc["system"].is<JsonObject>()) {
|
||||
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;
|
||||
}
|
||||
|
||||
JsonObject network = doc["network"];
|
||||
status_model.cargo_ap_ssid = String((const char *)(network["ap_ssid"] | "unknown"));
|
||||
status_model.cargo_sta_ip = String((const char *)(network["sta_ip"] | "n/a"));
|
||||
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()));
|
||||
}
|
||||
|
||||
String temps = "";
|
||||
JsonArray temp_array = doc["temps"];
|
||||
int shown_temps = 0;
|
||||
if (doc["temps"].is<JsonArray>()) {
|
||||
String temps = "";
|
||||
JsonArray temp_array = doc["temps"];
|
||||
int shown_temps = 0;
|
||||
|
||||
for (JsonObject temp : temp_array) {
|
||||
for (JsonObject temp : temp_array) {
|
||||
bool enabled = temp["enabled"] | false;
|
||||
bool online = temp["online"] | false;
|
||||
|
||||
@@ -318,21 +328,25 @@ static void parse_status_json(const String &body)
|
||||
temps += "\n";
|
||||
shown_temps++;
|
||||
|
||||
if (shown_temps >= 5) {
|
||||
break;
|
||||
if (shown_temps >= 5) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (temps.length() == 0) {
|
||||
temps = "No temp sensors reported";
|
||||
}
|
||||
|
||||
status_model.temps_text = temps;
|
||||
}
|
||||
|
||||
if (temps.length() == 0) {
|
||||
temps = "No temp sensors reported";
|
||||
}
|
||||
if (doc["relays"].is<JsonArray>()) {
|
||||
String outputs = "";
|
||||
JsonArray relay_array = doc["relays"];
|
||||
|
||||
String outputs = "";
|
||||
JsonArray relay_array = doc["relays"];
|
||||
relay_count = 0;
|
||||
|
||||
relay_count = 0;
|
||||
|
||||
for (JsonObject relay : relay_array) {
|
||||
for (JsonObject relay : relay_array) {
|
||||
const char *id = relay["id"] | "";
|
||||
const char *name = relay["name"] | relay["id"] | "Output";
|
||||
bool enabled = relay["enabled"] | false;
|
||||
@@ -360,18 +374,17 @@ static void parse_status_json(const String &body)
|
||||
outputs += on_off(state);
|
||||
}
|
||||
|
||||
outputs += "\n";
|
||||
outputs += "\n";
|
||||
}
|
||||
|
||||
if (outputs.length() == 0) {
|
||||
outputs = "No outputs reported";
|
||||
}
|
||||
|
||||
status_model.outputs_text = outputs;
|
||||
update_relay_buttons();
|
||||
}
|
||||
|
||||
if (outputs.length() == 0) {
|
||||
outputs = "No outputs reported";
|
||||
}
|
||||
|
||||
status_model.temps_text = temps;
|
||||
status_model.outputs_text = outputs;
|
||||
|
||||
update_relay_buttons();
|
||||
|
||||
Serial.println("Parsed status summary:");
|
||||
Serial.print(" SOC: ");
|
||||
Serial.println(status_model.soc);
|
||||
@@ -448,6 +461,58 @@ static void update_wifi_label()
|
||||
set_label_text_if_changed(wifi_label, last_wifi_text, text);
|
||||
}
|
||||
|
||||
static bool fetch_status_fields(const char *url, const char *label)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
set_label_text_if_changed(system_label, last_system_text, "API: waiting for WiFi");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.print("GET ");
|
||||
Serial.println(url);
|
||||
|
||||
HTTPClient http;
|
||||
http.setTimeout(5000);
|
||||
http.begin(url);
|
||||
int code = http.GET();
|
||||
|
||||
status_model.http_code = code;
|
||||
|
||||
Serial.print(label);
|
||||
Serial.print(" HTTP code: ");
|
||||
Serial.println(code);
|
||||
|
||||
if (code == 200) {
|
||||
String body = http.getString();
|
||||
|
||||
Serial.print(label);
|
||||
Serial.print(" body length: ");
|
||||
Serial.println(body.length());
|
||||
|
||||
parse_status_json(body);
|
||||
http.end();
|
||||
return true;
|
||||
}
|
||||
|
||||
status_model.api_ok = false;
|
||||
|
||||
String system;
|
||||
system += "API: error\n";
|
||||
system += label;
|
||||
system += "\nHTTP: ";
|
||||
system += String(code);
|
||||
if (code <= 0) {
|
||||
system += "\n";
|
||||
system += http.errorToString(code);
|
||||
}
|
||||
|
||||
Serial.println(system);
|
||||
set_label_text_if_changed(system_label, last_system_text, system);
|
||||
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void poll_status_api()
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
@@ -455,61 +520,15 @@ static void poll_status_api()
|
||||
return;
|
||||
}
|
||||
|
||||
if (millis() - last_status_poll_ms < 5000) {
|
||||
return;
|
||||
if (millis() - last_status_poll_ms >= 2000) {
|
||||
last_status_poll_ms = millis();
|
||||
fetch_status_fields(CARGO_API_FAST_STATUS_URL, "fast status");
|
||||
}
|
||||
|
||||
last_status_poll_ms = millis();
|
||||
|
||||
String requesting;
|
||||
requesting += "API: requesting\n";
|
||||
requesting += "/api/v1/status\n";
|
||||
requesting += "Dashboard IP:\n";
|
||||
requesting += WiFi.localIP().toString();
|
||||
set_label_text_if_changed(system_label, last_system_text, requesting);
|
||||
|
||||
Serial.print("GET ");
|
||||
Serial.println(CARGO_API_STATUS_URL);
|
||||
|
||||
HTTPClient http;
|
||||
http.setTimeout(5000);
|
||||
http.begin(CARGO_API_STATUS_URL);
|
||||
int code = http.GET();
|
||||
|
||||
status_model.http_code = code;
|
||||
|
||||
Serial.print("HTTP code: ");
|
||||
Serial.println(code);
|
||||
|
||||
if (code == 200) {
|
||||
String body = http.getString();
|
||||
|
||||
Serial.print("Body length: ");
|
||||
Serial.println(body.length());
|
||||
Serial.println(body);
|
||||
|
||||
String received;
|
||||
received += "API: received\nHTTP: 200\nBytes: ";
|
||||
received += String(body.length());
|
||||
set_label_text_if_changed(system_label, last_system_text, received);
|
||||
|
||||
parse_status_json(body);
|
||||
} else {
|
||||
status_model.api_ok = false;
|
||||
|
||||
String system;
|
||||
system += "API: error\nHTTP: ";
|
||||
system += String(code);
|
||||
if (code <= 0) {
|
||||
system += "\n";
|
||||
system += http.errorToString(code);
|
||||
}
|
||||
|
||||
Serial.println(system);
|
||||
set_label_text_if_changed(system_label, last_system_text, system);
|
||||
if (millis() - last_metadata_poll_ms >= 30000) {
|
||||
last_metadata_poll_ms = millis();
|
||||
fetch_status_fields(CARGO_API_SLOW_STATUS_URL, "slow status");
|
||||
}
|
||||
|
||||
http.end();
|
||||
}
|
||||
|
||||
static lv_obj_t *create_card(lv_obj_t *parent, const char *title, int width, int height, lv_align_t align, int x, int y)
|
||||
@@ -624,7 +643,7 @@ static void create_overland_status_screen()
|
||||
lv_obj_align(touch_count_label, LV_ALIGN_TOP_LEFT, 0, 142);
|
||||
|
||||
lv_obj_t *footer = lv_label_create(screen);
|
||||
lv_label_set_text(footer, "Polling Cargo ESP /api/v1/status every 5 seconds");
|
||||
lv_label_set_text(footer, "Fast: battery/temps/relays every 2s | Slow: system/config/network every 30s");
|
||||
lv_obj_set_style_text_color(footer, lv_color_hex(0x7D8996), 0);
|
||||
lv_obj_set_width(footer, 900);
|
||||
lv_obj_set_style_text_align(footer, LV_TEXT_ALIGN_CENTER, 0);
|
||||
|
||||
Reference in New Issue
Block a user