Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
750be28
feat: 🎸 implement base music
tusgino Nov 8, 2025
8564a23
refactor: update music playback functionality to use song_id instead …
tusgino Nov 8, 2025
38b96ba
Merge pull request #1 from ostgr/feat/tu_music
tusgino Nov 9, 2025
d48e9ec
fix: 🐛 resample after play music
tusgino Nov 9, 2025
0ce889d
Mute audio when config wifi
MinhQuan7 Nov 20, 2025
26c7ebd
add bluetooth and e-ra iot
MinhQuan7 Nov 22, 2025
0c34eea
Merge remote-tracking branch 'origin/feature/musicQuan' into feat/mus…
MinhQuan7 Nov 22, 2025
f6fe0f8
Add Bluetooth mcp tool
MinhQuan7 Nov 27, 2025
8845b91
processing add custom web server config OTA URL
MinhQuan7 Dec 13, 2025
27a98cf
done ver 1: Web server config design
MinhQuan7 Dec 15, 2025
82ed961
add iotforce puppy board and enhanced visualization of web server
MinhQuan7 Dec 23, 2025
70f9abb
done fix issues related display and movement
MinhQuan7 Dec 23, 2025
7d65da8
add behavior of puppy - full react and add calibration mcp
MinhQuan7 Dec 24, 2025
b423469
add behavior handshake and another react cute
MinhQuan7 Dec 25, 2025
e2f9911
add mcp voice access to config wifi mode
MinhQuan7 Dec 25, 2025
109398a
add monitoring voltage of battery
MinhQuan7 Dec 25, 2025
70523ad
add selection ERA Smart Home on menuconfig
MinhQuan7 Dec 29, 2025
b3f6090
add standby screen theme
MinhQuan7 Dec 29, 2025
59aac1c
clean directory
MinhQuan7 Dec 29, 2025
a82d17c
done standby
MinhQuan7 Dec 29, 2025
fefe834
clean code - remove any issues
MinhQuan7 Dec 29, 2025
0dbb0a6
Merge branch 'feat/musicIoT-Bluetooth' of https://github.com/ostgr/xi…
MinhQuan7 Dec 29, 2025
55d8557
done standby theme design
MinhQuan7 Dec 29, 2025
d8a5723
done fix issues hide standby theme
MinhQuan7 Dec 29, 2025
6ec85c5
add font 7digit to standby theme
MinhQuan7 Dec 30, 2025
1b632eb
add humidity value to standby
MinhQuan7 Dec 30, 2025
86a0314
add update with custom ota url - storage on aws
MinhQuan7 Jan 9, 2026
2af4974
done add 2.8inch board and add scan sdcard documentation feature
MinhQuan7 Jan 14, 2026
10daf87
Update
MinhQuan7 Jan 14, 2026
e4d23ae
upgrade puppy
MinhQuan7 Jan 16, 2026
82a82eb
add new feature - extract documentation from sdcard - quiz mode
MinhQuan7 Jan 19, 2026
e1853d1
change method quiz mode to using server quiz mode
MinhQuan7 Jan 21, 2026
995f459
supply server quiz
MinhQuan7 Jan 21, 2026
a23a5de
add FOTA Feature
MinhQuan7 Feb 2, 2026
b42afeb
fix error when run
MinhQuan7 Feb 2, 2026
0f9895b
upgrade new algorithms movements
MinhQuan7 Feb 2, 2026
61291d7
upgrade with new version movement and upgrade OTA
MinhQuan7 Feb 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,20 @@ main/assets/lang_config.h
main/mmap_generate_emoji.h
.DS_Store
.cache

*.pyc
*.bin
mmap_generate_*.h
.clangd
main/features/weather/weather_config.h
quiz_server/node_modules/
quiz_server/.env
quiz_server/package-lock.json

# Node Modules
node_modules/
**/node_modules/
fota_server_next/.next/
fota_server_next/out/
fota_server_next/build/
*.log
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)

set(PROJECT_VER "2.0.4")
set(PROJECT_VER "2.0.5")

# 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)
Expand Down
Binary file added FACE_DESIGN.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
76 changes: 76 additions & 0 deletions README_Rotation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Display Rotation & UI Alignment Guide

This guide explains how to configure the default display rotation (specifically 270°) and ensures UI elements remain centered and properly aligned across different orientations.

## 1. Setting Default Rotation (Auto Default 270°)

The default rotation is configured in the board initialization file ensuring the display starts in landscape mode.

### Implementation Location
File: `main/boards/iotforce-xiaozhi-iot-vietnam-es3n28p-lcd-2.8/iotforce_xiaozhi_iot_vietnam_es3n28p_lcd_2.8.cc`

### How it works
In the `InitializeTouch()` method (or constructor), the LVGL display rotation is explicitly set to 270 degrees:

```cpp
// Store LVGL display handle for rotation
g_lvgl_display = lv_display_get_default();
if (g_lvgl_display != NULL)
{
// Set default rotation to 270° (landscape mode)
lv_display_set_rotation(g_lvgl_display, LV_DISPLAY_ROTATION_270);
}
```

This ensures that upon boot, the screen coordinates are mapped to 270° (Landscape), where:
- **Width** becomes 320px
- **Height** becomes 240px

## 2. Ensuring Elements Remain Centered (Fix UI Position)

To guarantee that UI elements (like the boot logo, status bar, or chat bubbles) remain centered regardless of rotation (0°, 90°, 180°, 270°), follow these three rules:

### Rule A: Use Percentage-Based Sizing
Avoid hardcoding pixel widths (e.g., `320px`). Instead, use `LV_PCT(100)`. This allows the container to resize automatically when the screen dimensions flip between Portrait and Landscape.

**Example (`main/display/lcd_display.cc`):**
```cpp
// BAD: Fixed width
lv_obj_set_width(content_, 240);

// GOOD: Responsive width
lv_obj_set_width(content_, LV_PCT(100)); // Adapts to 240px or 320px automatically
```

### Rule B: Use Flex Layouts for Automatic Alignment
Flex layouts allow children to center themselves dynamically without manual coordinate calculation.

**Example (Centering Status Bar Elements):**
```cpp
// Create container
lv_obj_t* status_bar = lv_obj_create(parent);

// 1. Set Flex Flow (Row or Column)
lv_obj_set_flex_flow(status_bar, LV_FLEX_FLOW_ROW);

// 2. Set Alignment (Horizontal, Vertical, Row Gap)
// LV_FLEX_ALIGN_SPACE_BETWEEN: Spreads items to edges
// LV_FLEX_ALIGN_CENTER: Centers items vertically
lv_obj_set_flex_align(status_bar, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
```

### Rule C: Use Center Constraints for Floating Objects
For single objects like a Loading Spinner or Logo that float above the content, use `lv_obj_center()` or alignment flags ensuring they stay relative to the parent's center.

**Example:**
```cpp
lv_obj_t* loader = lv_spinner_create(screen);
lv_obj_center(loader); // Always stays in the mathematical center (w/2, h/2)
```

## 3. Gestures for Rotation
The current firmware includes a built-in gesture to rotate the screen manually for testing:
- **Action**: Hold **two fingers** on the screen for > 0.2 seconds.
- **Result**: Cycles rotation 0° -> 90° -> 180° -> 270°.

This confirms that if your UI follows the rules above, it will look correct in all orientations instantly.
14 changes: 14 additions & 0 deletions ROLE_introduction.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Tôi là {{assistant_name}}. Khi được gọi, hãy chào: "Rất vui khi lại được gặp bạn".
Tôi là trợ lý AI thông minh, am hiểu nhiều lĩnh vực từ Khoa học, Công nghệ (AI, IoT), Ngôn ngữ đến Đời sống xã hội. Phong cách của tôi luôn vui vẻ, gần gũi, truyền cảm hứng nhưng cũng rất gãy gọn và logic.

QUAN TRỌNG - QUY TẮC BẮT BUỘC:
1. ĐỐI VỚI LỆNH DI CHUYỂN HOẶC ĐIỀU KHIỂN ĐỘNG TÁC:
- THỰC HIỆN NGAY và TUYỆT ĐỐI IM LẶNG
- KHÔNG NÓI TRƯỚC: Cấm nói "Tôi sẽ tiến X bước", "Được, tôi sẽ...", "Ok tôi hiểu..."
- KHÔNG NÓI SAU: Cấm nói "Tôi đã hoàn thành", "Xong rồi", "Bạn cần gì thêm không?"
- CHỈ GỌI TOOL, KHÔNG OUTPUT TEXT. Ví dụ: "tiến 5 bước" → gọi tool với steps=5, không nói gì
2. Luôn chụp ảnh khi được yêu cầu. Với các lệnh phát nhạc/media, thực hiện nhanh và hạn chế giao tiếp thừa.
3. **IMPORTANT**: If calling tools, output ONLY the function call, with NO extra commentary or text.

Khi dạy học hay giải thích, tôi luôn đi từ tổng quan đến chi tiết, dùng ví dụ sinh động.
Nếu không nghe rõ hoặc được mời subscribe/nhắc đến "La La school", tôi sẽ khéo léo yêu cầu nhắc lại mà không đề cập đến tên các kênh đó.
10 changes: 10 additions & 0 deletions check_kconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

try:
with open('main/Kconfig.projbuild', 'r', encoding='utf-8') as f:
content = f.read()
if "Đèn" in content:
print("Found 'Đèn' in main/Kconfig.projbuild")
else:
print("Not found 'Đèn' in main/Kconfig.projbuild")
except Exception as e:
print(f"Error: {e}")
15 changes: 15 additions & 0 deletions check_sdkconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

try:
with open('sdkconfig', 'rb') as f:
content = f.read()
try:
content.decode('cp1252')
print("sdkconfig is valid cp1252")
except UnicodeDecodeError as e:
print(f"sdkconfig error: {e}")
# print context around the error
start = max(0, e.start - 20)
end = min(len(content), e.end + 20)
print(f"Context: {content[start:end]}")
except FileNotFoundError:
print("sdkconfig not found")
176 changes: 176 additions & 0 deletions docs/ADDING_CONFIGURABLE_FEATURES_VN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Hướng dẫn: Thêm tính năng Configurable trong Menuconfig (ESP-IDF)

Tài liệu này hướng dẫn chi tiết cách tạo một tùy chọn cấu hình (Configuration Option) để bật/tắt tính năng thông qua `idf.py menuconfig`, và cách viết code sao cho **tất cả các board** đều sử dụng được mà không cần sửa từng file board riêng lẻ.

## 1. Tổng quan luồng dữ liệu (The Flow)

Trước khi bắt đầu, hãy hiểu cách hệ thống hoạt động:

1. **Kconfig File (`main/Kconfig.projbuild`)**: Bạn định nghĩa menu và biến cấu hình tại đây.
2. **idf.py menuconfig**: Người dùng chạy lệnh này, giao diện hiện ra, họ chọn Enable/Disable.
3. **Build System**: Khi biên dịch, ESP-IDF sẽ đọc lựa chọn của người dùng và tạo ra file header `sdkconfig.h`.
4. **C++ Code**: Code của bạn `#include "sdkconfig.h"` (thường được include tự động) và kiểm tra các macro `CONFIG_...` để quyết định biên dịch đoạn code nào.

**Sơ đồ:**
`Kconfig.projbuild` -> `idf.py menuconfig` -> `sdkconfig` (file lưu) -> `sdkconfig.h` (Auto-gen) -> `Code C++`

---

## 2. Bước 1: Định nghĩa trong Kconfig

File cần chỉnh sửa: `main/Kconfig.projbuild`
Đây là nơi chứa các cấu hình riêng cho dự án Xiaozhi.

**Ví dụ:** Chúng ta sẽ làm tính năng **"Cảnh báo pin yếu bằng giọng nói"** (Voice Low Battery Warning).

Mở `main/Kconfig.projbuild` và thêm đoạn sau (nên thêm vào cuối file hoặc trong một `menu` phù hợp):

```kconfig
menu "Battery Features" # Tạo một menu con tên là Battery Features

config ENABLE_LOW_BATTERY_VOICE
bool "Enable Low Battery Voice Warning" # Tên hiển thị trong menu
default y # Mặc định là Bật (y=yes, n=no)
help
If enabled, the device will speak a warning when battery is low.
# Dòng giải thích chi tiết tính năng làm gì

config LOW_BATTERY_THRESHOLD
int "Low Battery Threshold (%)" # Cho phép nhập số
range 5 50 # Giới hạn từ 5% đến 50%
default 20 # Mặc định 20%
depends on ENABLE_LOW_BATTERY_VOICE # Chỉ hiện khi option trên được BẬT
help
The percentage at which the warning triggers.

endmenu
```

**Giải thích:**

- `config ENABLE_LOW_BATTERY_VOICE`: Đây là tên biến. Trong code C++, nó sẽ tự động thêm tiền tố `CONFIG_` -> `CONFIG_ENABLE_LOW_BATTERY_VOICE`.
- `bool`: Kiểu dữ liệu đúng/sai.
- `depends on`: Rất hay, giúp ẩn hiện menu con dựa trên menu cha.

---

## 3. Bước 2: Triển khai Code (Architecture)

Để code chạy được trên **mọi board**, nguyên tắc vàng là: **Không viết logic vào file board cụ thể (như `wifi_board.cc`)**.

Hãy viết logic vào lớp `Application` (lớp quản lý chung) hoặc một lớp quản lý riêng (Manager). Các lớp này sẽ gọi xuống `Board` thông qua **Interface** (lớp cha `Board`).

### Ví dụ triển khai trong `main/application.cc`

Chúng ta sẽ sửa file `main/application.cc`.

**Bước 2.1: Kiểm tra Config lúc biên dịch (Compile-time check)**

Sử dụng `#ifdef` để trình biên dịch biết có nên đưa đoạn code này vào firmware hay không. Điều này giúp tiết kiệm Flash nếu tính năng bị tắt.

```cpp
// main/application.cc

// ... các include khác ...
#include "board.h"
#include "sdkconfig.h" // Đảm bảo đã include file này

void Application::CheckBatteryStatus() {
// Lấy instance của Board (Singleton Pattern)
// Đây là cách code chạy được trên mọi board: Nó gọi hàm ảo GetBatteryLevel
auto& board = Board::GetInstance();

int level;
bool charging, discharging;

// Gọi hàm chung của Board
if (board.GetBatteryLevel(level, charging, discharging)) {

// --- BẮT ĐẦU ĐOẠN CODE CẤU HÌNH ---

#ifdef CONFIG_ENABLE_LOW_BATTERY_VOICE
// Đoạn code này chỉ được biên dịch nếu bạn chọn "Y" trong menuconfig

// Lấy ngưỡng từ menuconfig (CONFIG_LOW_BATTERY_THRESHOLD)
if (discharging && level <= CONFIG_LOW_BATTERY_THRESHOLD) {
// Giả sử hàm PlaySound có tồn tại
PlaySound(Lang::Sounds::OGG_LOW_BATTERY);
ESP_LOGW(TAG, "Low battery warning triggered at %d%%", level);
}
#endif

// --- KẾT THÚC ĐOẠN CODE CẤU HÌNH ---
}
}
```

**Giải thích:**

- `Board::GetInstance()`: Trả về đối tượng board hiện tại (dù là board S3 Box, board Wifi, hay board Custom).
- `#ifdef CONFIG_...`: Nếu người dùng tắt tính năng này, trình biên dịch sẽ vứt bỏ đoạn code bên trong, giúp firmware nhẹ hơn.
- `CONFIG_LOW_BATTERY_THRESHOLD`: Giá trị `int` bạn đã đặt trong Kconfig được thay thế trực tiếp vào đây.

---

## 4. Bước 3: Xử lý Runtime (Nếu cần)

Đôi khi bạn muốn biên dịch code vào nhưng chỉ tắt nó đi dựa trên logic chạy. Nhưng với yêu cầu "Enable trong menuconfig", cách dùng `#ifdef` ở trên là chuẩn nhất.

Tuy nhiên, nếu bạn muốn code sạch hơn (tránh quá nhiều `#ifdef` lồng nhau), bạn có thể dùng `IS_ENABLED` (nếu ESP-IDF hỗ trợ macro này) hoặc viết như sau:

```cpp
// Một cách viết khác hiện đại hơn (C++17 if constexpr - nếu trình biên dịch hỗ trợ)
// Hoặc đơn giản là if thường (trình biên dịch thông minh sẽ tự tối ưu code chết)

void Application::SomeFunction() {
#if CONFIG_ENABLE_LOW_BATTERY_VOICE
bool voice_enabled = true;
#else
bool voice_enabled = false;
#endif

if (voice_enabled) {
// Logic here
}
}
```

---

## 5. Tóm tắt các file cần chỉnh sửa

Để thực hiện một tính năng trọn vẹn:

1. **`main/Kconfig.projbuild`**:

- _Nhiệm vụ:_ Tạo giao diện bật tắt cho người dùng.
- _Kết quả:_ Tạo ra các macro `CONFIG_TEN_TINH_NANG`.

2. **`main/application.h`** (Nếu cần thêm biến/hàm mới):

- _Nhiệm vụ:_ Khai báo hàm mới.
- _Lưu ý:_ Cũng nên bọc `#ifdef` quanh khai báo hàm nếu hàm đó chỉ tồn tại khi bật tính năng.

3. **`main/application.cc`** (Hoặc file logic chính):

- _Nhiệm vụ:_ Thực thi logic.
- _Cách gọi:_ Sử dụng `Board::GetInstance()` để tương tác phần cứng, dùng `#ifdef` để kiểm tra cấu hình.

4. **`main/boards/common/board.h`** (Nếu tính năng cần phần cứng mới):
- _Nhiệm vụ:_ Định nghĩa Interface chung (ví dụ: `virtual void TurnOnFan() = 0;`).

---

## 6. Ví dụ thực tế: Flow gọi nhau

Giả sử bạn bật tính năng trên. Flow sẽ chạy như sau:

1. **Khởi động:** `main.cc` gọi `Application::GetInstance().Start()`.
2. **Vòng lặp:** `Application` có một Timer hoặc Loop kiểm tra trạng thái.
3. **Kiểm tra:** Trong hàm kiểm tra, nó gặp `#ifdef CONFIG_ENABLE_LOW_BATTERY_VOICE`.
4. **Tiền xử lý:**
- Nếu trong menuconfig chọn **Yes**: Trình biên dịch thấy đoạn code bên trong. Nó gọi `Board::GetInstance().GetBatteryLevel()`.
- Nếu trong menuconfig chọn **No**: Trình biên dịch xóa sạch đoạn code đó. Firmware không hề biết tính năng này tồn tại.
5. **Đa hình (Polymorphism):** Khi gọi `Board::GetInstance()`, nếu bạn đang nạp code cho board `bread-compact-wifi`, nó sẽ trả về instance của class `CompactWifiBoard`. Nếu nạp cho `esp-box`, nó trả về `EspBoxBoard`. Code logic trong `Application` không thay đổi.

Đây là cách kiến trúc **Platform Agnostic** (Độc lập nền tảng) hoạt động.
Loading