diff --git a/CMakeLists.txt b/CMakeLists.txt index 68745d0351..d31232505a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,15 @@ set(PROJECT_VER "2.0.4") # Add this line to disable the specific warning add_compile_options(-Wno-missing-field-initializers) +if(WIN32) + set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES ON) + set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES ON) + set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS ON) + set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS ON) + set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES ON) + set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES ON) + set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON) +endif() include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(xiaozhi) diff --git a/docs/UX_UI_CONCEPT.md b/docs/UX_UI_CONCEPT.md new file mode 100644 index 0000000000..981eda0df7 --- /dev/null +++ b/docs/UX_UI_CONCEPT.md @@ -0,0 +1,120 @@ +# UI/UX Design System & Concept + +Tài liệu này mô tả chi tiết hệ thống thiết kế (Design System) của dự án, bao gồm màu sắc, typography, bố cục và phong cách thành phần. Sử dụng tài liệu này để đảm bảo tính đồng bộ khi phát triển các hệ thống vệ tinh hoặc mở rộng tính năng. + +## 1. Triết lý thiết kế (Design Philosophy) +Hệ thống hướng tới phong cách **Modern, Clean & Soft** (Hiện đại, Sạch sẽ & Mềm mại). +- **Màu sắc**: Sử dụng tông màu tím (Violet) làm chủ đạo, tạo cảm giác công nghệ nhưng nhẹ nhàng, không gay gắt. +- **Hình khối**: Bo góc lớn (Rounded), đổ bóng sâu (Deep Shadows) tạo chiều sâu không gian. +- **Tương phản**: Hỗ trợ tốt cả Light Mode và Dark Mode với độ tương phản được tinh chỉnh kỹ lưỡng (Off-white thay vì Pure white). + +--- + +## 2. Bảng màu (Color Palette) + +Hệ thống sử dụng Tailwind CSS với bảng màu được tùy biến (`tailwind.config.js`). + +### Primary Color (Màu chủ đạo - Violet) +Dùng cho các nút hành động chính (CTA), trạng thái active, và điểm nhấn thương hiệu. +- **DEFAULT**: `#8B6FB5` (Màu tím trung tính, dịu mắt) +- **Light (50-200)**: `#F5F3F8` (Nền nhẹ), `#DDD6E8` +- **Dark (700-900)**: `#6B4F8A`, `#4A2F5C` (Dùng cho text trên nền sáng) + +### Secondary / Neutral (Màu trung tính - Slate/Gray) +Dùng cho văn bản, đường viền, và nền phụ. +- **DEFAULT**: `#6B7280` +- **Background Light**: `#FAFAF9` (Warm Off-white - Trắng ngà ấm, không phải trắng tinh #FFFFFF) +- **Background Dark**: `#1A1A1A` (Deep Charcoal - Đen than, không phải đen tuyền #000000) +- **Foreground (Text)**: `#FFFFFF` (Trên nền tối) / `#111827` (Trên nền sáng) + +### Semantic Colors (Màu ngữ nghĩa) +- **Success (Thành công)**: `#34D399` (Xanh ngọc) +- **Warning (Cảnh báo)**: `#FBBF24` (Vàng hổ phách) +- **Danger (Nguy hiểm/Lỗi)**: `#F43F5E` (Đỏ hồng) + +--- + +## 3. Typography (Kiểu chữ & Tỷ lệ) + +### Font Family +Sử dụng System Font Stack (San Francisco, Segoe UI, Roboto, Inter) để tối ưu hiệu năng và độ rõ nét trên từng hệ điều hành. + +### Text Styles +- **Headings (Tiêu đề)**: + - Font weight: `Bold` hoặc `Semibold`. + - Letter spacing: `tracking-tight` (Khoảng cách chữ hẹp để tạo khối vững chắc). + - Gradient Text: Các tiêu đề lớn thường sử dụng hiệu ứng gradient dọc. + - Ví dụ Violet: `from-[#A78BC8] to-[#8B6FB5]` +- **Body (Nội dung)**: + - Size: `text-base` (16px) hoặc `text-sm` (14px). + - Color: `text-default-600` (Màu xám trung tính, không dùng đen tuyền để tránh mỏi mắt). + +### Kích thước (Scale) +- **Display**: `text-4xl` đến `text-6xl` (36px - 60px) +- **H1/Title**: `text-3xl` (30px) +- **Subtitle**: `text-lg` đến `text-xl` (18px - 20px) + +--- + +## 4. Layout & Spacing (Bố cục & Khoảng cách) + +### Grid & Container +- **Max Width**: `max-w-7xl` (1280px) cho nội dung chính. +- **Padding chuẩn**: `px-6 py-8` (24px ngang, 32px dọc). + +### Sidebar Layout +- **Width**: `16rem` (256px) trên Desktop. +- **Behavior**: + - Desktop: Cố định bên trái (`md:ml-64`). + - Mobile: Ẩn/Hiện dạng Drawer hoặc thu gọn. +- **Transition**: `duration-300` (Mượt mà khi đóng mở). + +### Spacing (Khoảng cách) +Sử dụng hệ thống 4px grid của Tailwind. +- **Gap nhỏ**: `gap-3` (12px) cho các item trong list. +- **Padding Card**: `p-6` (24px) hoặc `md:p-8` (32px). +- **Margin Section**: `my-6` (24px). + +--- + +## 5. Component Styling (Phong cách thành phần) + +### Cards (Thẻ nội dung) +- **Background**: + - Light: `#FFFFFF` (Trắng tinh trên nền Off-white). + - Dark: `#default-100` hoặc `#1A1A1A`. +- **Border Radius**: `rounded-lg` (Bo góc lớn, mềm mại). +- **Shadow (Đổ bóng)**: + - Mặc định: `shadow-xl` (Bóng đổ rộng, tạo cảm giác nổi hẳn lên nền). + - Hover: `shadow-2xl`. +- **Animation**: `animate-scaleIn` (Hiệu ứng phóng to nhẹ khi xuất hiện). + +### Navigation (Menu) +- **Active Item**: + - Background: `bg-primary` (Màu tím chủ đạo). + - Text: `text-primary-foreground` (Trắng). + - Bo góc: `rounded-lg`. +- **Inactive Item**: + - Text: `text-default-600`. + - Hover: `hover:bg-default-100` (Xám nhạt). +- **Icons**: Kích thước chuẩn `22px`. + +### Inputs & Forms +- **Nền**: Trong suốt hoặc xám rất nhạt. +- **Border**: Mỏng, màu `#E4E7EB`. +- **Focus**: Highlight viền màu Primary (`#8B6FB5`). + +### Visual Effects (Hiệu ứng thị giác) +- **Glassmorphism**: Sử dụng cho Footer hoặc Overlay. + - `bg-default-50/50` (Độ trong suốt 50%). + - `backdrop-blur` (nếu cần). +- **Gradients**: Sử dụng tinh tế cho Text hoặc Button Background, tránh dùng mảng lớn gây rối mắt. + +--- + +## 6. Tổng kết cho Designer/Developer +Khi thiết kế hệ thống mới đồng bộ với hệ thống này, hãy tuân thủ: +1. **Giữ nền sạch**: Dùng màu Off-white (`#FAFAF9`), tránh dùng màu xám quá đậm hoặc trắng quá chói làm nền chính. +2. **Màu tím là điểm nhấn**: Chỉ dùng màu tím (`#8B6FB5`) cho những thứ quan trọng (Nút bấm, Link, Active State). +3. **Bo góc và Đổ bóng**: Đừng ngại dùng `rounded-lg` và `shadow-xl`, đây là đặc trưng tạo nên sự mềm mại của giao diện. +4. **Không gian thoáng**: Luôn giữ padding rộng rãi (`p-6`, `p-8`) trong các Card chứa nội dung. diff --git a/docs/mcp-bluetooth-guide-vi.md b/docs/mcp-bluetooth-guide-vi.md new file mode 100644 index 0000000000..c95b4f9008 --- /dev/null +++ b/docs/mcp-bluetooth-guide-vi.md @@ -0,0 +1,97 @@ +# Hướng dẫn Tích hợp Điều khiển Bluetooth KCX_BT_EMITTER qua MCP + +Tài liệu này hướng dẫn cách tích hợp module phát Bluetooth KCX_BT_EMITTER V1.7 vào hệ thống Xiaozhi ESP32 sử dụng giao thức MCP (Model Context Protocol). + +## 1. Kết nối Phần cứng + +Bạn cần kết nối module KCX_BT_EMITTER với ESP32 như sau: + +| Chân Module Bluetooth | Chân ESP32 (Mặc định) | Mô tả | +| ----------------------- | --------------------- | -------------------------------- | +| **5V** | 5V | Nguồn điện | +| **GND** | GND | Nối đất | +| **CONNECT** (hoặc PAIR) | **GPIO 18** | Chân điều khiển kết nối (Output) | +| **LINK** | **GPIO 19** | Chân trạng thái kết nối (Input) | +| **AUDIO_L/R** | DAC/Audio Out | Tín hiệu âm thanh | + +> **Lưu ý:** Bạn có thể thay đổi chân GPIO trong file code nếu sơ đồ đi dây của bạn khác. + +## 2. Triển khai Code MCP + +Chúng tôi đã tích hợp trực tiếp các công cụ điều khiển vào `main/mcp_server.cc`. + +### Các thay đổi đã thực hiện: + +1. **Khai báo thư viện và chân GPIO:** + Đã thêm thư viện `driver/gpio.h` và định nghĩa chân kết nối: + + ```cpp + #include + + // Cấu hình chân Bluetooth + #define BLUETOOTH_CONNECT_PIN GPIO_NUM_18 + #define BLUETOOTH_LINK_PIN GPIO_NUM_19 + ``` + +2. **Khởi tạo GPIO:** + Trong hàm `McpServer::AddCommonTools`, chúng tôi đã thêm đoạn code để cấu hình: + + - `BLUETOOTH_CONNECT_PIN`: Chế độ Output, mặc định mức High (giả sử kích hoạt mức thấp). + - `BLUETOOTH_LINK_PIN`: Chế độ Input để đọc trạng thái. + +3. **Thêm các công cụ MCP (Tools):** + + - **`self.bluetooth.connect`**: + + - **Chức năng:** Kích hoạt chế độ kết nối hoặc tìm kiếm thiết bị. + - **Hoạt động:** Tạo một xung thấp (Low pulse) ngắn (100ms) trên chân CONNECT, tương đương với việc nhấn nút PAIR. + + - **`self.bluetooth.disconnect`**: + + - **Chức năng:** Ngắt kết nối hoặc xóa bộ nhớ ghép nối. + - **Hoạt động:** Giữ chân CONNECT ở mức thấp trong 3 giây (Long press). + + - **`self.bluetooth.get_status`**: + - **Chức năng:** Kiểm tra xem Bluetooth đã kết nối chưa. + - **Hoạt động:** Đọc trạng thái chân LINK. (High = Connected, Low = Disconnected). + +## 3. Cách sử dụng + +Sau khi nạp code và khởi động lại thiết bị, bạn có thể ra lệnh bằng giọng nói hoặc qua giao diện chat: + +- **Kết nối:** "Hãy kết nối bluetooth" hoặc "Bật bluetooth". +- **Kiểm tra:** "Kiểm tra trạng thái bluetooth" hoặc "Bluetooth đã kết nối chưa?". +- **Ngắt kết nối:** "Ngắt kết nối bluetooth" hoặc "Tắt bluetooth". + +## 4. Tùy chỉnh + +Để thay đổi chân GPIO, hãy mở file `main/mcp_server.cc` và sửa các dòng sau ở đầu file: + +```cpp +#define BLUETOOTH_CONNECT_PIN GPIO_NUM_18 // Đổi số 18 thành chân bạn dùng +#define BLUETOOTH_LINK_PIN GPIO_NUM_19 // Đổi số 19 thành chân bạn dùng +``` + +## 5. Luồng hoạt động của MCP điều khiển phần cứng + +Để tự triển khai thêm các điều khiển phần cứng khác, bạn có thể làm theo quy trình sau: + +1. **Xác định phần cứng:** Chọn chân GPIO và cách thức điều khiển (High/Low, PWM, v.v.). +2. **Viết code điều khiển:** Sử dụng các hàm của ESP-IDF như `gpio_set_level`, `gpio_get_level`. +3. **Đăng ký Tool trong `McpServer::AddCommonTools`:** + - Đặt tên tool (ví dụ: `self.relay.turn_on`). + - Viết mô tả rõ ràng để AI hiểu khi nào cần dùng. + - Định nghĩa tham số (nếu có). + - Viết hàm xử lý (lambda function) thực hiện hành động phần cứng. + +Ví dụ mẫu: + +```cpp +AddTool("self.my_device.action", + "Mô tả hành động", + PropertyList(), + [](const PropertyList &properties) -> ReturnValue { + // Code điều khiển phần cứng ở đây + return "Thành công"; + }); +``` diff --git a/docs/webserver_knowledge.md b/docs/webserver_knowledge.md new file mode 100644 index 0000000000..60bd4b2d3c --- /dev/null +++ b/docs/webserver_knowledge.md @@ -0,0 +1,272 @@ +# Web Server và OTA trên Xiaozhi Firmware + +Tài liệu này mô tả chi tiết cách hệ thống Web Server và OTA hiện tại hoạt động, đồng thời hướng dẫn cách tùy biến (custom) để thêm tính năng cài đặt URL OTA riêng. + +--- + +## 1. Tổng quan hệ thống hiện tại + +### 1.1. Web Server hoạt động như thế nào? + +Hệ thống sử dụng thư viện `esp_http_server` của ESP-IDF để chạy một web server nhẹ ngay trên chip ESP32. + +- **Khởi tạo:** Server được khởi tạo trong `main/ota_server.cc` thông qua hàm `OtaServer::Start(int port)`. Mặc định lắng nghe ở cổng 80. +- **Giao diện (Frontend):** Các file HTML (như `ota_index.html`) không được lưu dưới dạng file trên thẻ nhớ mà được **nhúng trực tiếp vào Firmware** dưới dạng mảng byte (binary) trong quá trình biên dịch (sử dụng tính năng `EMBED_FILES` của CMake). + - Trong code C++, chúng được truy cập qua biến ngoại lai: `extern const uint8_t ota_index_html_start[]`. +- **Xử lý (Backend):** Các đường dẫn (URI) được đăng ký với các hàm xử lý (Handler). + - `GET /ota`: Trả về nội dung file HTML. + - `POST /ota_upload`: Nhận file firmware upload từ trình duyệt. + +### 1.2. Cơ chế lưu trữ cấu hình (NVS) + +Khi người dùng thay đổi cấu hình trên Web (ví dụ: Wifi, MQTT), dữ liệu không được lưu vào file text mà được ghi vào vùng nhớ **NVS (Non-Volatile Storage)** trong Flash. + +**Quy trình lưu dữ liệu:** + +1. **Web (Client):** Gửi HTTP POST request chứa dữ liệu (JSON hoặc Form data). +2. **RAM (Server):** Chip nhận dữ liệu vào bộ đệm. +3. **NVS Wrapper:** Class `Settings` (`main/settings.cc`) được dùng để đơn giản hóa việc gọi API của ESP-IDF. +4. **Flash:** Hàm `nvs_set_str` và `nvs_commit` sẽ ghi dữ liệu vĩnh viễn xuống chip. + +### 1.3. Quy trình OTA (Over-The-Air) + +Logic OTA nằm trong `main/ota.cc`. + +1. **Check Version:** Thiết bị gửi thông tin (MAC, Version hiện tại) lên Server. +2. **Response:** Server trả về JSON chứa: + - Version mới nhất. + - URL tải firmware. + - Cấu hình MQTT/WebSocket mới (nếu có). +3. **Upgrade:** Nếu có version mới, thiết bị tải file `.bin` từ URL và ghi vào phân vùng OTA tiếp theo. + +--- + +## 2. Hướng dẫn Custom: Thêm tính năng cài đặt URL OTA tùy chỉnh (Local OTA Server) + +Mục tiêu: Thêm một ô nhập liệu trên trang Web cấu hình để người dùng có thể trỏ thiết bị sang Server OTA riêng của họ. + +### Bước 1: Sửa đổi Frontend (HTML/JS) + +Bạn cần sửa file HTML gốc (ví dụ `main/web/ota_index.html` hoặc tạo mới nếu dự án đang dùng file binary có sẵn). + +Thêm đoạn mã sau vào vị trí mong muốn trong thẻ ``: + +```html +
+

Cấu hình OTA Server Riêng

+
+ + +
+ +
+ + +``` + +### Bước 2: Cập nhật Backend Header (`main/ota_server.h`) + +Khai báo hàm xử lý mới trong class `OtaServer`. + +```cpp +class OtaServer { +public: + // ... (giữ nguyên code cũ) + +private: + // ... (giữ nguyên code cũ) + + // THÊM DÒNG NÀY + static esp_err_t HandleSaveOtaUrl(httpd_req_t* req); +}; +``` + +### Bước 3: Cập nhật Backend Implementation (`main/ota_server.cc`) + +**1. Đăng ký đường dẫn (URI) mới:** + +Trong hàm `OtaServer::Start`: + +```cpp +esp_err_t OtaServer::Start(int port) { + // ... (giữ nguyên code khởi tạo server) + + // Đăng ký URI mới + httpd_uri_t save_ota_url_uri = { + .uri = "/api/save_ota_url", // Phải khớp với fetch() trong JS + .method = HTTP_POST, + .handler = HandleSaveOtaUrl, // Hàm xử lý bên dưới + .user_ctx = nullptr + }; + httpd_register_uri_handler(server_handle_, &save_ota_url_uri); + + return ESP_OK; +} +``` + +**2. Viết hàm xử lý logic:** + +Thêm hàm này vào cuối file `ota_server.cc`: + +```cpp +#include "settings.h" // Bắt buộc include để dùng NVS + +esp_err_t OtaServer::HandleSaveOtaUrl(httpd_req_t* req) { + char content[256]; // Bộ đệm chứa URL + + // 1. Nhận dữ liệu từ trình duyệt + // Cắt bớt nếu dữ liệu dài hơn bộ đệm + size_t recv_size = std::min(req->content_len, sizeof(content) - 1); + + int ret = httpd_req_recv(req, content, recv_size); + if (ret <= 0) { + if (ret == HTTPD_SOCK_ERR_TIMEOUT) { + httpd_resp_send_408(req); + } + return ESP_FAIL; + } + content[ret] = '\0'; // Kết thúc chuỗi ký tự + + ESP_LOGI(kTag, "Nhận được Custom OTA URL: %s", content); + + // 2. Lưu vào NVS (Flash) + // "wifi" là namespace (bạn có thể chọn namespace khác nếu muốn) + // true: cho phép ghi (Read-Write) + Settings settings("wifi", true); + settings.SetString("ota_url", std::string(content)); + + // 3. Phản hồi OK cho trình duyệt + httpd_resp_send(req, "OK", HTTPD_RESP_USE_STRLEN); + return ESP_OK; +} +``` + +### Bước 4: Kiểm tra tích hợp (`main/ota.cc`) + +Hệ thống hiện tại đã có sẵn logic để đọc key `ota_url` này. Bạn có thể kiểm tra trong hàm `Ota::GetCheckVersionUrl()`: + +```cpp +std::string Ota::GetCheckVersionUrl() { + Settings settings("wifi", false); // Mở NVS để đọc + std::string url = settings.GetString("ota_url"); // Đọc key chúng ta vừa lưu + + if (url.empty()) { + url = CONFIG_OTA_URL; // Nếu không có, dùng mặc định + } + return url; +} +``` + +--- + +## 3. Phân tích Giao diện Cấu hình Wifi (Captive Portal) + +Giao diện cấu hình Wifi đẹp mắt (màu tối, hiệu ứng neon) mà bạn thấy khi kết nối vào Wifi của thiết bị (192.168.4.1) **KHÔNG** nằm trong `main/ota_server.cc`. Nó nằm trong một component riêng biệt. + +### 3.1. Vị trí mã nguồn + +Giao diện này thuộc về component `TienHuyIoT_esp-wifi-connect`. + +- **Frontend (HTML/CSS/JS):** `managed_components/TienHuyIoT_esp-wifi-connect/assets/wifi_configuration.html` +- **Backend (C++):** `managed_components/TienHuyIoT_esp-wifi-connect/wifi_configuration_ap.cc` + +### 3.2. Cấu trúc Frontend (`wifi_configuration.html`) + +Đây là một file "All-in-One" chứa: + +- **HTML:** Cấu trúc trang web, các tab (Wifi Config, Advanced), các form nhập liệu. +- **CSS:** Style giao diện (class `.card`, `.page`, biến màu `--accent`...). +- **JavaScript:** + - Biến `translations`: Từ điển đa ngôn ngữ (Việt, Anh, Trung...). + - Hàm `switchTab()`: Chuyển đổi giữa tab Wifi và Advanced. + - Hàm `submitAdvancedForm()`: Gom dữ liệu từ form Advanced thành JSON và gửi POST lên `/advanced/submit`. + +### 3.3. Cấu trúc Backend (`wifi_configuration_ap.cc`) + +File này xử lý logic của Web Server khi ở chế độ AP (Access Point). + +- **Đăng ký URI:** + - `/`: Trả về nội dung file `wifi_configuration.html`. + - `/advanced/config` (GET): Trả về JSON chứa cấu hình hiện tại (để điền vào form khi mới load trang). + - `/advanced/submit` (POST): Nhận JSON từ form Advanced và lưu vào NVS. + +### 3.4. Quy trình phát triển tính năng mới (Dev Flow) + +Để thêm một tính năng mới vào trang cấu hình này (ví dụ: thêm ô nhập "API Token"), bạn hãy làm theo các bước sau: + +#### Bước 0: Chuẩn bị môi trường (Quan trọng) + +Vì code nằm trong `managed_components`, nó sẽ bị ghi đè nếu bạn update component. +**Giải pháp:** Copy thư mục `TienHuyIoT_esp-wifi-connect` từ `managed_components/` ra thư mục `components/` (tạo mới ở root dự án). Khi đó, ESP-IDF sẽ ưu tiên dùng bản local của bạn. + +#### Bước 1: Sửa Frontend (`wifi_configuration.html`) + +1. Mở file HTML. +2. Tìm đến `
`. +3. Thêm HTML cho ô nhập liệu mới: + ```html +

+ + +

+ ``` +4. (Tùy chọn) Thêm từ khóa vào biến `translations` trong thẻ `