10 KiB
Dark Theme Configuration
English
Overview
The Xiaozhi ESP32 project includes a built-in theme system with two available themes:
- Light Theme (default)
- Dark Theme
The theme setting is stored in the device's NVS (Non-Volatile Storage) and persists across reboots.
Available Themes
Light Theme
- Background: White (
#FFFFFF) - Text: Black (
#000000) - Chat Background: Light Gray (
#E0E0E0) - User Bubble: Green (
#00FF00) - Assistant Bubble: Light Gray (
#DDDDDD) - Border: Black (
#000000)
Dark Theme
- Background: Black (
#000000) - Text: White (
#FFFFFF) - Chat Background: Dark Gray (
#1F1F1F) - User Bubble: Green (
#00FF00) - Assistant Bubble: Dark Gray (
#222222) - Border: White (
#FFFFFF) - Low Battery: Red (
#FF0000)
How Themes Work
The theme system is implemented in the display layer:
- Theme configuration is defined in
main/display/lcd_display.cc - Theme preference is stored in NVS under the namespace
"display"with key"theme" - Default theme is
"light"if no NVS value exists - Themes are registered with the
LvglThemeManagerat initialization
Setting Dark Theme as Default
There are several ways to set the dark theme as default:
Method 1: Via MCP Protocol (Recommended)
If your device supports MCP (Model Context Protocol), you can change the theme using the self.screen.set_theme tool:
{
"theme": "dark"
}
This will immediately switch to dark theme and save the preference to NVS.
Method 2: Modify NVS Partition Before Flashing
- Create or modify an NVS partition CSV file with the theme setting:
key,type,encoding,value
display,namespace,,
theme,data,string,dark
- Generate the NVS binary:
python $IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py generate nvs.csv nvs.bin 0x4000
- Flash the NVS partition to your device:
esptool.py --chip esp32s3 --port /dev/ttyUSB0 write_flash 0x9000 nvs.bin
Note: The NVS partition address (0x9000) may vary depending on your board's partition table. Check your partitions.csv file for the correct address.
Method 3: Modify NVS at Runtime
You can modify the NVS storage programmatically by adding code to set the theme preference during initialization:
#include "settings.h"
// In your initialization code
Settings settings("display", true);
settings.SetString("theme", "dark");
Method 4: Modify Default in Source Code
If you want to change the default theme in the source code, modify main/display/lcd_display.cc:
// Find this line (around line 74):
std::string theme_name = settings.GetString("theme", "light");
// Change the default from "light" to "dark":
std::string theme_name = settings.GetString("theme", "dark");
Then rebuild and flash the firmware.
Why No Menuconfig Option?
The theme setting is implemented as a runtime configuration stored in NVS rather than a compile-time configuration. This design choice allows:
- Runtime Changes: Users can switch themes without reflashing firmware
- User Preferences: Each device can maintain its own theme preference
- Remote Control: Themes can be changed via MCP protocol or other remote interfaces
- Persistence: Theme preference survives firmware updates (when NVS partition is preserved)
If a menuconfig option is desired, it could be added to set the default theme when NVS is empty, but the current architecture favors runtime configurability.
Implementation Details
The theme system consists of several components:
-
Theme Base Class (
main/display/display.h)- Abstract base class for all themes
- Stores theme name
-
LvglTheme Class (
main/display/lvgl_display/lvgl_theme.h)- Implements theme for LVGL-based displays
- Stores colors, fonts, and styling information
-
LvglThemeManager (
main/display/lvgl_display/lvgl_theme.h)- Singleton manager for registered themes
- Provides theme lookup by name
-
Settings Class (
main/settings.h)- Wrapper for NVS storage operations
- Handles reading/writing theme preferences
-
Display Initialization (
main/display/lcd_display.cc)- Registers available themes
- Loads theme preference from NVS
- Applies theme to display
Troubleshooting
Theme doesn't persist after reboot
- Ensure NVS partition is properly initialized
- Check that the NVS partition is not being erased during flash operations
- Verify Settings class is opened with
read_write = truewhen setting values
Dark theme not available
- Verify your board uses LCD display (themes are not implemented for OLED displays)
- Check that
InitializeLcdThemes()is being called during display initialization - Ensure you're using a recent version of the firmware
Cannot change theme via MCP
- Verify MCP protocol is enabled and working
- Check that your display supports the theme system (should have
GetTheme() != nullptr) - Review MCP server logs for errors
Future Enhancements
Possible future improvements to the theme system:
- Custom themes loaded from assets partition
- Additional built-in themes
- Per-element theme customization via MCP
- Theme preview before applying
- Automatic theme switching based on time of day
中文
概述
小智 ESP32 项目内置了主题系统,提供两种可用主题:
- 浅色主题(默认)
- 深色主题
主题设置存储在设备的 NVS(非易失性存储)中,重启后保持不变。
可用主题
浅色主题
- 背景:白色 (
#FFFFFF) - 文本:黑色 (
#000000) - 聊天背景:浅灰色 (
#E0E0E0) - 用户气泡:绿色 (
#00FF00) - 助手气泡:浅灰色 (
#DDDDDD) - 边框:黑色 (
#000000)
深色主题
- 背景:黑色 (
#000000) - 文本:白色 (
#FFFFFF) - 聊天背景:深灰色 (
#1F1F1F) - 用户气泡:绿色 (
#00FF00) - 助手气泡:深灰色 (
#222222) - 边框:白色 (
#FFFFFF) - 低电量:红色 (
#FF0000)
主题工作原理
主题系统在显示层实现:
- 主题配置定义在
main/display/lcd_display.cc - 主题偏好存储在 NVS 中,命名空间为
"display",键为"theme" - 如果 NVS 中没有值,默认主题为
"light" - 主题在初始化时注册到
LvglThemeManager
将深色主题设置为默认
有几种方法可以将深色主题设置为默认:
方法 1:通过 MCP 协议(推荐)
如果您的设备支持 MCP(模型上下文协议),可以使用 self.screen.set_theme 工具更改主题:
{
"theme": "dark"
}
这将立即切换到深色主题并将偏好保存到 NVS。
方法 2:烧录前修改 NVS 分区
- 创建或修改带有主题设置的 NVS 分区 CSV 文件:
key,type,encoding,value
display,namespace,,
theme,data,string,dark
- 生成 NVS 二进制文件:
python $IDF_PATH/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py generate nvs.csv nvs.bin 0x4000
- 将 NVS 分区烧录到设备:
esptool.py --chip esp32s3 --port /dev/ttyUSB0 write_flash 0x9000 nvs.bin
注意: NVS 分区地址(0x9000)可能因开发板的分区表而异。请检查您的 partitions.csv 文件以获取正确的地址。
方法 3:运行时修改 NVS
您可以通过编程方式修改 NVS 存储,在初始化期间添加代码来设置主题偏好:
#include "settings.h"
// 在初始化代码中
Settings settings("display", true);
settings.SetString("theme", "dark");
方法 4:修改源代码中的默认值
如果您想在源代码中更改默认主题,请修改 main/display/lcd_display.cc:
// 找到这一行(大约在第 74 行):
std::string theme_name = settings.GetString("theme", "light");
// 将默认值从 "light" 改为 "dark":
std::string theme_name = settings.GetString("theme", "dark");
然后重新构建并烧录固件。
为什么没有 Menuconfig 选项?
主题设置作为运行时配置存储在 NVS 中,而不是编译时配置。这种设计选择的优点:
- 运行时更改:用户可以在不重新烧录固件的情况下切换主题
- 用户偏好:每个设备可以保持自己的主题偏好
- 远程控制:可以通过 MCP 协议或其他远程接口更改主题
- 持久性:主题偏好在固件更新时保留(当 NVS 分区被保留时)
如果需要 menuconfig 选项,可以添加一个选项来设置 NVS 为空时的默认主题,但当前架构更倾向于运行时可配置性。
实现细节
主题系统由几个组件组成:
-
主题基类 (
main/display/display.h)- 所有主题的抽象基类
- 存储主题名称
-
LvglTheme 类 (
main/display/lvgl_display/lvgl_theme.h)- 为基于 LVGL 的显示器实现主题
- 存储颜色、字体和样式信息
-
LvglThemeManager (
main/display/lvgl_display/lvgl_theme.h)- 已注册主题的单例管理器
- 按名称提供主题查找
-
Settings 类 (
main/settings.h)- NVS 存储操作的包装器
- 处理主题偏好的读写
-
显示初始化 (
main/display/lcd_display.cc)- 注册可用主题
- 从 NVS 加载主题偏好
- 将主题应用到显示器
故障排除
重启后主题不保持
- 确保 NVS 分区已正确初始化
- 检查在烧录操作期间 NVS 分区未被擦除
- 验证设置值时 Settings 类以
read_write = true打开
深色主题不可用
- 验证您的开发板使用 LCD 显示器(主题未针对 OLED 显示器实现)
- 检查在显示初始化期间是否调用了
InitializeLcdThemes() - 确保您使用的是最新版本的固件
无法通过 MCP 更改主题
- 验证 MCP 协议已启用并正常工作
- 检查您的显示器支持主题系统(应该有
GetTheme() != nullptr) - 查看 MCP 服务器日志中的错误
未来增强
主题系统可能的未来改进:
- 从资源分区加载自定义主题
- 额外的内置主题
- 通过 MCP 进行逐元素主题自定义
- 应用前的主题预览
- 基于时间的自动主题切换