feat(travel): Enhance MTR arrival handling with retry logic and improve UI update efficiency

This commit is contained in:
GW_MC
2026-02-03 20:49:42 +08:00
parent 3617a206ff
commit 6c4050e9d4
4 changed files with 100 additions and 32 deletions

View File

@@ -116,7 +116,26 @@ MtrArrivalErrorCode MTRNextTrainHandler::get_next_arrival_info(
// Create HTTP client configuration // Create HTTP client configuration
esp_http_client_config_t http_config = {}; esp_http_client_config_t http_config = {};
http_config.url = url_str.c_str(); http_config.url = url_str.c_str();
http_config.timeout_ms = 10000; http_config.timeout_ms = 15000;
http_config.transport_type = HTTP_TRANSPORT_OVER_SSL;
http_config.crt_bundle_attach = esp_crt_bundle_attach;
// Retry logic for connection failures
constexpr int MAX_RETRIES = 2;
esp_err_t err = ESP_FAIL;
char* buffer = nullptr;
int total_len = 0;
for (int retry = 0; retry <= MAX_RETRIES; retry++) {
if (retry > 0) {
ESP_LOGW(TAG, "Retrying HTTP request (%d/%d)", retry, MAX_RETRIES);
vTaskDelay(pdMS_TO_TICKS(500));
}
// Create HTTP client configuration for each attempt
esp_http_client_config_t http_config = {};
http_config.url = url_str.c_str();
http_config.timeout_ms = 15000;
http_config.transport_type = HTTP_TRANSPORT_OVER_SSL; http_config.transport_type = HTTP_TRANSPORT_OVER_SSL;
http_config.crt_bundle_attach = esp_crt_bundle_attach; http_config.crt_bundle_attach = esp_crt_bundle_attach;
@@ -124,22 +143,30 @@ MtrArrivalErrorCode MTRNextTrainHandler::get_next_arrival_info(
auto http_handler = network_handler->get_http_handler(std::move(http_config)); auto http_handler = network_handler->get_http_handler(std::move(http_config));
if (!http_handler) { if (!http_handler) {
ESP_LOGE(TAG, "Failed to create HTTP handler"); ESP_LOGE(TAG, "Failed to create HTTP handler");
return MtrArrivalErrorCode::UNKNOWN; continue;
} }
esp_err_t err = http_handler->perform_request(); err = http_handler->perform_request();
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err)); ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err));
return MtrArrivalErrorCode::NO_ARRIVAL_INFO; continue;
} }
// Get response body // Get response body
char* buffer = nullptr;
int total_len = 0;
http_handler->get_body(buffer, total_len); http_handler->get_body(buffer, total_len);
if (!buffer || total_len <= 0) { if (buffer && total_len > 0) {
ESP_LOGE(TAG, "Empty response from MTR API"); break;
}
if (buffer) {
free(buffer);
buffer = nullptr;
}
}
if (err != ESP_OK || !buffer || total_len <= 0) {
ESP_LOGE(TAG, "Failed to get response after retries");
if (buffer) { if (buffer) {
free(buffer); free(buffer);
} }

View File

@@ -167,8 +167,11 @@ void MainUI::update_arrivals(const std::vector<RouteArrivalData>& arrival_data)
if (i < static_cast<int>(arrival_data.size())) { if (i < static_cast<int>(arrival_data.size())) {
update_route_display_(route_displays_[i], arrival_data[i]); update_route_display_(route_displays_[i], arrival_data[i]);
} else { } else {
// Hide unused route displays // Hide unused route displays if currently visible
if (route_displays_[i].cached_visible) {
lv_obj_add_flag(route_displays_[i].container, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(route_displays_[i].container, LV_OBJ_FLAG_HIDDEN);
route_displays_[i].cached_visible = false;
}
} }
} }
@@ -176,37 +179,59 @@ void MainUI::update_arrivals(const std::vector<RouteArrivalData>& arrival_data)
} }
void MainUI::update_route_display_(RouteDisplay& display, const RouteArrivalData& data) { void MainUI::update_route_display_(RouteDisplay& display, const RouteArrivalData& data) {
// Show container if hidden
if (!display.cached_visible) {
lv_obj_clear_flag(display.container, LV_OBJ_FLAG_HIDDEN); lv_obj_clear_flag(display.container, LV_OBJ_FLAG_HIDDEN);
display.cached_visible = true;
}
// Update header with line color // Update header with line color
std::string header_text = data.route.station_name + "" + data.route.direction_name; std::string header_text = data.route.station_name + "" + data.route.direction_name;
if (header_text != display.cached_header_text) {
lv_label_set_text(display.header, header_text.c_str()); lv_label_set_text(display.header, header_text.c_str());
display.cached_header_text = header_text;
}
if (!data.route.line_color.empty()) { if (!data.route.line_color.empty()) {
lv_color_t line_color = hex_to_lv_color_(data.route.line_color); lv_color_t line_color = hex_to_lv_color_(data.route.line_color);
lv_obj_set_style_text_color(display.header, line_color, 0); lv_obj_set_style_text_color(display.header, line_color, 0);
} }
// Update arrival labels // Update arrival labels - only if text changed
for (int i = 0; i < MAX_ARRIVALS_PER_ROUTE; i++) { for (int i = 0; i < MAX_ARRIVALS_PER_ROUTE; i++) {
if (i < static_cast<int>(data.arrivals.size())) { std::string arrival_text = "";
bool should_show = (i < static_cast<int>(data.arrivals.size()));
if (should_show) {
const auto& arrival = data.arrivals[i]; const auto& arrival = data.arrivals[i];
std::string arrival_text = " " + arrival.arrival_time; arrival_text = " " + arrival.arrival_time;
if (!arrival.arrival_time_full.empty()) { if (!arrival.arrival_time_full.empty()) {
arrival_text += " (" + arrival.arrival_time_full + ")"; arrival_text += " (" + arrival.arrival_time_full + ")";
} }
arrival_text += " " + arrival.direction; arrival_text += " " + arrival.direction;
}
if (arrival_text != display.cached_arrival_texts[i]) {
lv_label_set_text(display.arrival_labels[i], arrival_text.c_str()); lv_label_set_text(display.arrival_labels[i], arrival_text.c_str());
display.cached_arrival_texts[i] = arrival_text;
}
// Handle visibility
if (should_show) {
if (lv_obj_has_flag(display.arrival_labels[i], LV_OBJ_FLAG_HIDDEN)) {
lv_obj_clear_flag(display.arrival_labels[i], LV_OBJ_FLAG_HIDDEN); lv_obj_clear_flag(display.arrival_labels[i], LV_OBJ_FLAG_HIDDEN);
}
} else { } else {
lv_label_set_text(display.arrival_labels[i], ""); if (!lv_obj_has_flag(display.arrival_labels[i], LV_OBJ_FLAG_HIDDEN)) {
lv_obj_add_flag(display.arrival_labels[i], LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(display.arrival_labels[i], LV_OBJ_FLAG_HIDDEN);
} }
} }
}
// Show error if any // Show error if any
if (!data.is_valid && !data.error_message.empty()) { if (!data.is_valid && !data.error_message.empty()) {
lv_label_set_text(display.arrival_labels[0], (" 錯誤: " + data.error_message).c_str()); std::string error_text = " 錯誤: " + data.error_message;
lv_label_set_text(display.arrival_labels[0], error_text.c_str());
lv_obj_clear_flag(display.arrival_labels[0], LV_OBJ_FLAG_HIDDEN); lv_obj_clear_flag(display.arrival_labels[0], LV_OBJ_FLAG_HIDDEN);
} }
} }

View File

@@ -43,6 +43,11 @@ private:
lv_obj_t* container = nullptr; lv_obj_t* container = nullptr;
lv_obj_t* header = nullptr; lv_obj_t* header = nullptr;
lv_obj_t* arrival_labels[3] = {nullptr, nullptr, nullptr}; // Show up to 3 arrivals per route lv_obj_t* arrival_labels[3] = {nullptr, nullptr, nullptr}; // Show up to 3 arrivals per route
// Cached values for change detection
std::string cached_header_text;
std::string cached_arrival_texts[3];
bool cached_visible = false;
}; };
RouteDisplay route_displays_[5]; RouteDisplay route_displays_[5];

View File

@@ -258,7 +258,18 @@ std::string MainUIHandler::format_arrival_time_(const std::string& api_time) {
return time_part; return time_part;
} }
return api_time; // Try to find HH:MM pattern in the string
for (size_t i = 0; i < api_time.length() - 5; i++) {
if (api_time[i] == ':' && i > 0 && i < api_time.length() - 3) {
std::string candidate = api_time.substr(i - 2, 5);
if (isdigit(candidate[0]) && isdigit(candidate[1]) && candidate[2] == ':' &&
isdigit(candidate[3]) && isdigit(candidate[4])) {
return candidate;
}
}
}
return ""; // Return empty instead of raw input
} }
std::string MainUIHandler::format_arrival_time_full_(const std::string& api_time) { std::string MainUIHandler::format_arrival_time_full_(const std::string& api_time) {
@@ -280,8 +291,8 @@ std::string MainUIHandler::get_current_time_string_() {
auto now = std::time(nullptr); auto now = std::time(nullptr);
auto tm = *std::localtime(&now); auto tm = *std::localtime(&now);
char buffer[9]; // HH:MM:SS\0 char buffer[6]; // HH:MM\0
strftime(buffer, sizeof(buffer), "%H:%M:%S", &tm); strftime(buffer, sizeof(buffer), "%H:%M", &tm);
return std::string(buffer); return std::string(buffer);
} }