mirror of
https://github.com/78/xiaozhi-esp32.git
synced 2026-07-21 02:05:52 +00:00
fix(electron-bot): show chat subtitle on display (#2042)
* Enhance Otto Robot camera support by adding configuration for OV3660. Updated config.h to define camera types and GPIO settings, modified config.json to include new camera options, and refactored otto_robot.cc for improved camera detection and initialization logic. * fix: 移除 OttoEmojiDisplay 构造函数中的 SetTheme 调用以修复 LoadProhibited 崩溃 Made-with: Cursor * refactor: improve audio service error handling and codec timeout management - Updated AudioService to prevent input task termination on read timeout, introducing a delay instead. - Enhanced NoAudioCodec to implement a read timeout for I2S channel reads. - Adjusted WebSocketControlServer to set a control port for improved socket management. - Added manufacturer information to the config.json for waveshare ESP32-Touch-LCD-3.5. * fix(otto): WebSocket direct clients not receiving MCP responses When a browser connects directly to the WebSocket control server (port 8080) and sends a JSON-RPC request, the MCP response was routed through Application::SendMcpMessage -> protocol_->SendMcpMessage, which sends it to the cloud protocol channel. As a result, the direct WebSocket client never received the response, while the WeChat mini-program could because it communicates via the cloud. Fix: - Add BroadcastMessage() to WebSocketControlServer, using httpd_queue_work + httpd_ws_send_frame_async to asynchronously send responses back to all connected clients on port 8080 - Add RegisterMcpBroadcastCallback() to Application, allowing an additional MCP send callback to be registered; SendMcpMessage() now invokes it alongside the cloud protocol - Register the broadcast callback in OttoRobot after the WebSocket server starts successfully Also add WebSocket direct-connect API documentation to README.md with complete JSON-RPC 2.0 command examples. * fix(otto-robot): migrate camera backend and set safe dark default theme - Migrate `otto-robot` camera backend from `EspVideo` to `Esp32Camera` to improve capture stability after reboot/power cycle. - Keep runtime sensor detection for both OV2640 and OV3660, and rename PID macros with `OTTO_` prefix to avoid symbol conflicts. - Configure camera output as `RGB565 + FRAMESIZE_240X240` to match the 240x240 display. - Rotate OV2640 output by 180 degrees (`VFlip + HMirror`) for correct orientation. - Simplify `otto-robot` camera sdkconfig options by keeping only: - `CONFIG_CAMERA_OV2640=y` - `CONFIG_CAMERA_OV3660=y` - Move Otto default dark theme setup into `OttoEmojiDisplay::SetupUI()` (after base UI init) to avoid boot-time LVGL null-object crash caused by calling `SetTheme()` too early. * feat(motion): smooth action ending and adaptive homing on otto/electron-bot Improve servo motion transitions to reduce abrupt returns to home pose. Replace linear interpolation with ease-out movement, make homing duration adaptive to angle delta, and skip intermediate homing when queued actions are pending to keep multi-action sequences fluid. * fix(electron-bot): show chat subtitle on display ElectronEmojiDisplay overrode SetupChatLabel() to delete the parent's chat_message_label_ (which lives inside bottom_bar_) and recreate it on the bottom-layer container_ without alignment. As a result the real subtitle label was hidden behind emoji_box_/top_bar_, while SetChatMessage() only toggled the now-empty bottom_bar_, so chat subtitles were never visible. Reuse the parent label created in bottom_bar_ (matching otto-robot) and only switch to the dark theme in SetupUI(), removing the custom SetupChatLabel(). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(electron-bot): restore status icons on standby and clean up display - SetStatus() did not re-show network_label_/battery_label_ when returning to STANDBY, so the WiFi and battery icons stayed hidden after listening or speaking. Restore them on standby to match otto-robot. - Remove the unused InitializeElectronEmojis() method and its declaration. - Drop unused includes (vector, assets.h, emoji_collection.h, lvgl_image.h) and add the missing trailing newline in the header. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,12 +3,8 @@
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "assets.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "display/lvgl_display/emoji_collection.h"
|
||||
#include "display/lvgl_display/lvgl_image.h"
|
||||
#include "display/lvgl_display/lvgl_theme.h"
|
||||
|
||||
#define TAG "ElectronEmojiDisplay"
|
||||
@@ -24,43 +20,20 @@ void ElectronEmojiDisplay::SetupUI() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Call parent SetupUI() first to create all lvgl objects (including container_)
|
||||
// Call parent SetupUI() first to create all lvgl objects (including container_,
|
||||
// bottom_bar_ and chat_message_label_)
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
// Setup chat label after parent UI is initialized so that container_ is valid
|
||||
SetupChatLabel();
|
||||
// UI 对象创建完成后切换主题(复用父类创建好的字幕标签,不再重建)
|
||||
auto* dark_theme = LvglThemeManager::GetInstance().GetTheme("dark");
|
||||
if (dark_theme != nullptr) {
|
||||
SetTheme(dark_theme);
|
||||
}
|
||||
|
||||
// Set default emotion after UI is initialized
|
||||
SetEmotion("staticstate");
|
||||
}
|
||||
|
||||
void ElectronEmojiDisplay::InitializeElectronEmojis() {
|
||||
ESP_LOGI(TAG, "Electron表情初始化将由Assets系统处理");
|
||||
// 表情初始化已移至assets系统,通过DEFAULT_EMOJI_COLLECTION=otto-gif配置
|
||||
// assets.cc会从assets分区加载GIF表情并设置到theme
|
||||
// Note: Default emotion is now set in SetupUI() after LVGL objects are created
|
||||
}
|
||||
|
||||
void ElectronEmojiDisplay::SetupChatLabel() {
|
||||
// Create/recreate the chat label under the display lock
|
||||
{
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
if (chat_message_label_) {
|
||||
lv_obj_del(chat_message_label_);
|
||||
}
|
||||
|
||||
chat_message_label_ = lv_label_create(container_);
|
||||
lv_label_set_text(chat_message_label_, "");
|
||||
lv_obj_set_width(chat_message_label_, width_ * 0.9);
|
||||
lv_label_set_long_mode(chat_message_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_obj_set_style_text_align(chat_message_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_color(chat_message_label_, lv_color_white(), 0);
|
||||
}
|
||||
// SetTheme acquires DisplayLockGuard internally, so call it after releasing the lock above
|
||||
SetTheme(LvglThemeManager::GetInstance().GetTheme("dark"));
|
||||
}
|
||||
|
||||
LV_FONT_DECLARE(OTTO_ICON_FONT);
|
||||
void ElectronEmojiDisplay::SetStatus(const char* status) {
|
||||
auto lvgl_theme = static_cast<LvglTheme*>(current_theme_);
|
||||
@@ -94,6 +67,8 @@ void ElectronEmojiDisplay::SetStatus(const char* status) {
|
||||
lv_obj_set_style_text_font(status_label_, text_font, 0);
|
||||
lv_label_set_text(status_label_, "");
|
||||
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(network_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(battery_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,4 @@ class ElectronEmojiDisplay : public SpiLcdDisplay {
|
||||
virtual ~ElectronEmojiDisplay() = default;
|
||||
virtual void SetStatus(const char* status) override;
|
||||
virtual void SetupUI() override;
|
||||
|
||||
private:
|
||||
void InitializeElectronEmojis();
|
||||
void SetupChatLabel();
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user