v1.6.6: Set MCP as default IoT Protocol (#690)
This commit is contained in:
parent
0c83263762
commit
d80f94387a
@ -4,7 +4,7 @@
|
|||||||
# CMakeLists in this exact order for cmake to work correctly
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
set(PROJECT_VER "1.6.5")
|
set(PROJECT_VER "1.6.6")
|
||||||
|
|
||||||
# Add this line to disable the specific warning
|
# Add this line to disable the specific warning
|
||||||
add_compile_options(-Wno-missing-field-initializers)
|
add_compile_options(-Wno-missing-field-initializers)
|
||||||
|
|||||||
@ -158,10 +158,10 @@ choice BOARD_TYPE
|
|||||||
bool "乐鑫ESP S3 LCD EV Board开发板"
|
bool "乐鑫ESP S3 LCD EV Board开发板"
|
||||||
config BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI
|
config BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI
|
||||||
bool "征辰科技1.54(WIFI)"
|
bool "征辰科技1.54(WIFI)"
|
||||||
config BOARD_TYPE_MINSI_K08_DUAL
|
|
||||||
bool "敏思科技K08(DUAL)"
|
|
||||||
config BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307
|
config BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307
|
||||||
bool "征辰科技1.54(ML307)"
|
bool "征辰科技1.54(ML307)"
|
||||||
|
config BOARD_TYPE_MINSI_K08_DUAL
|
||||||
|
bool "敏思科技K08(DUAL)"
|
||||||
config BOARD_TYPE_ESP32_S3_1_54_MUMA
|
config BOARD_TYPE_ESP32_S3_1_54_MUMA
|
||||||
bool "Spotpear ESP32-S3-1.54-MUMA"
|
bool "Spotpear ESP32-S3-1.54-MUMA"
|
||||||
endchoice
|
endchoice
|
||||||
@ -284,7 +284,7 @@ config USE_SERVER_AEC
|
|||||||
|
|
||||||
choice IOT_PROTOCOL
|
choice IOT_PROTOCOL
|
||||||
prompt "IoT Protocol"
|
prompt "IoT Protocol"
|
||||||
default IOT_PROTOCOL_XIAOZHI
|
default IOT_PROTOCOL_MCP
|
||||||
help
|
help
|
||||||
IoT 协议,用于获取设备状态与发送控制指令
|
IoT 协议,用于获取设备状态与发送控制指令
|
||||||
config IOT_PROTOCOL_MCP
|
config IOT_PROTOCOL_MCP
|
||||||
|
|||||||
@ -44,6 +44,14 @@ Application::Application() {
|
|||||||
event_group_ = xEventGroupCreate();
|
event_group_ = xEventGroupCreate();
|
||||||
background_task_ = new BackgroundTask(4096 * 7);
|
background_task_ = new BackgroundTask(4096 * 7);
|
||||||
|
|
||||||
|
#if CONFIG_USE_DEVICE_AEC
|
||||||
|
aec_mode_ = kAecOnDeviceSide;
|
||||||
|
#elif CONFIG_USE_SERVER_AEC
|
||||||
|
aec_mode_ = kAecOnServerSide;
|
||||||
|
#else
|
||||||
|
aec_mode_ = kAecOff;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_USE_AUDIO_PROCESSOR
|
#if CONFIG_USE_AUDIO_PROCESSOR
|
||||||
audio_processor_ = std::make_unique<AfeAudioProcessor>();
|
audio_processor_ = std::make_unique<AfeAudioProcessor>();
|
||||||
#else
|
#else
|
||||||
@ -285,7 +293,7 @@ void Application::ToggleChatState() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetListeningMode(realtime_chat_enabled_ ? kListeningModeRealtime : kListeningModeAutoStop);
|
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
|
||||||
});
|
});
|
||||||
} else if (device_state_ == kDeviceStateSpeaking) {
|
} else if (device_state_ == kDeviceStateSpeaking) {
|
||||||
Schedule([this]() {
|
Schedule([this]() {
|
||||||
@ -358,8 +366,8 @@ void Application::Start() {
|
|||||||
auto codec = board.GetAudioCodec();
|
auto codec = board.GetAudioCodec();
|
||||||
opus_decoder_ = std::make_unique<OpusDecoderWrapper>(codec->output_sample_rate(), 1, OPUS_FRAME_DURATION_MS);
|
opus_decoder_ = std::make_unique<OpusDecoderWrapper>(codec->output_sample_rate(), 1, OPUS_FRAME_DURATION_MS);
|
||||||
opus_encoder_ = std::make_unique<OpusEncoderWrapper>(16000, 1, OPUS_FRAME_DURATION_MS);
|
opus_encoder_ = std::make_unique<OpusEncoderWrapper>(16000, 1, OPUS_FRAME_DURATION_MS);
|
||||||
if (realtime_chat_enabled_) {
|
if (aec_mode_ != kAecOff) {
|
||||||
ESP_LOGI(TAG, "Realtime chat enabled, setting opus encoder complexity to 0");
|
ESP_LOGI(TAG, "AEC mode: %d, setting opus encoder complexity to 0", aec_mode_);
|
||||||
opus_encoder_->SetComplexity(0);
|
opus_encoder_->SetComplexity(0);
|
||||||
} else if (board.GetBoardType() == "ml307") {
|
} else if (board.GetBoardType() == "ml307") {
|
||||||
ESP_LOGI(TAG, "ML307 board detected, setting opus encoder complexity to 5");
|
ESP_LOGI(TAG, "ML307 board detected, setting opus encoder complexity to 5");
|
||||||
@ -404,6 +412,11 @@ void Application::Start() {
|
|||||||
// Initialize the protocol
|
// Initialize the protocol
|
||||||
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
|
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
|
||||||
|
|
||||||
|
// Add MCP common tools before initializing the protocol
|
||||||
|
#if CONFIG_IOT_PROTOCOL_MCP
|
||||||
|
McpServer::GetInstance().AddCommonTools();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ota_.HasMqttConfig()) {
|
if (ota_.HasMqttConfig()) {
|
||||||
protocol_ = std::make_unique<MqttProtocol>();
|
protocol_ = std::make_unique<MqttProtocol>();
|
||||||
} else if (ota_.HasWebsocketConfig()) {
|
} else if (ota_.HasWebsocketConfig()) {
|
||||||
@ -608,7 +621,7 @@ void Application::Start() {
|
|||||||
// Set the chat state to wake word detected
|
// Set the chat state to wake word detected
|
||||||
protocol_->SendWakeWordDetected(wake_word);
|
protocol_->SendWakeWordDetected(wake_word);
|
||||||
ESP_LOGI(TAG, "Wake word detected: %s", wake_word.c_str());
|
ESP_LOGI(TAG, "Wake word detected: %s", wake_word.c_str());
|
||||||
SetListeningMode(realtime_chat_enabled_ ? kListeningModeRealtime : kListeningModeAutoStop);
|
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
|
||||||
} else if (device_state_ == kDeviceStateSpeaking) {
|
} else if (device_state_ == kDeviceStateSpeaking) {
|
||||||
AbortSpeaking(kAbortReasonWakeWordDetected);
|
AbortSpeaking(kAbortReasonWakeWordDetected);
|
||||||
} else if (device_state_ == kDeviceStateActivating) {
|
} else if (device_state_ == kDeviceStateActivating) {
|
||||||
@ -1002,3 +1015,30 @@ void Application::SendMcpMessage(const std::string& payload) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::SetAecMode(AecMode mode) {
|
||||||
|
aec_mode_ = mode;
|
||||||
|
Schedule([this]() {
|
||||||
|
auto& board = Board::GetInstance();
|
||||||
|
auto display = board.GetDisplay();
|
||||||
|
switch (aec_mode_) {
|
||||||
|
case kAecOff:
|
||||||
|
audio_processor_->EnableDeviceAec(false);
|
||||||
|
display->ShowNotification(Lang::Strings::RTC_MODE_OFF);
|
||||||
|
break;
|
||||||
|
case kAecOnServerSide:
|
||||||
|
audio_processor_->EnableDeviceAec(false);
|
||||||
|
display->ShowNotification(Lang::Strings::RTC_MODE_ON);
|
||||||
|
break;
|
||||||
|
case kAecOnDeviceSide:
|
||||||
|
audio_processor_->EnableDeviceAec(true);
|
||||||
|
display->ShowNotification(Lang::Strings::RTC_MODE_ON);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the AEC mode is changed, close the audio channel
|
||||||
|
if (protocol_ && protocol_->IsAudioChannelOpened()) {
|
||||||
|
protocol_->CloseAudioChannel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -30,6 +30,12 @@
|
|||||||
#define SEND_AUDIO_EVENT (1 << 1)
|
#define SEND_AUDIO_EVENT (1 << 1)
|
||||||
#define CHECK_NEW_VERSION_DONE_EVENT (1 << 2)
|
#define CHECK_NEW_VERSION_DONE_EVENT (1 << 2)
|
||||||
|
|
||||||
|
enum AecMode {
|
||||||
|
kAecOff,
|
||||||
|
kAecOnDeviceSide,
|
||||||
|
kAecOnServerSide,
|
||||||
|
};
|
||||||
|
|
||||||
enum DeviceState {
|
enum DeviceState {
|
||||||
kDeviceStateUnknown,
|
kDeviceStateUnknown,
|
||||||
kDeviceStateStarting,
|
kDeviceStateStarting,
|
||||||
@ -73,6 +79,8 @@ public:
|
|||||||
void PlaySound(const std::string_view& sound);
|
void PlaySound(const std::string_view& sound);
|
||||||
bool CanEnterSleepMode();
|
bool CanEnterSleepMode();
|
||||||
void SendMcpMessage(const std::string& payload);
|
void SendMcpMessage(const std::string& payload);
|
||||||
|
void SetAecMode(AecMode mode);
|
||||||
|
AecMode GetAecMode() const { return aec_mode_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Application();
|
Application();
|
||||||
@ -90,11 +98,8 @@ private:
|
|||||||
esp_timer_handle_t clock_timer_handle_ = nullptr;
|
esp_timer_handle_t clock_timer_handle_ = nullptr;
|
||||||
volatile DeviceState device_state_ = kDeviceStateUnknown;
|
volatile DeviceState device_state_ = kDeviceStateUnknown;
|
||||||
ListeningMode listening_mode_ = kListeningModeAutoStop;
|
ListeningMode listening_mode_ = kListeningModeAutoStop;
|
||||||
#if CONFIG_USE_DEVICE_AEC || CONFIG_USE_SERVER_AEC
|
AecMode aec_mode_ = kAecOff;
|
||||||
bool realtime_chat_enabled_ = true;
|
|
||||||
#else
|
|
||||||
bool realtime_chat_enabled_ = false;
|
|
||||||
#endif
|
|
||||||
bool aborted_ = false;
|
bool aborted_ = false;
|
||||||
bool voice_detected_ = false;
|
bool voice_detected_ = false;
|
||||||
bool busy_decoding_audio_ = false;
|
bool busy_decoding_audio_ = false;
|
||||||
|
|||||||
@ -51,6 +51,9 @@
|
|||||||
|
|
||||||
"VOLUME": "Volume ",
|
"VOLUME": "Volume ",
|
||||||
"MUTED": "Muted",
|
"MUTED": "Muted",
|
||||||
"MAX_VOLUME": "Max volume"
|
"MAX_VOLUME": "Max volume",
|
||||||
|
|
||||||
|
"RTC_MODE_OFF": "AEC Off",
|
||||||
|
"RTC_MODE_ON": "AEC On"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,6 +50,9 @@
|
|||||||
|
|
||||||
"VOLUME": "音量 ",
|
"VOLUME": "音量 ",
|
||||||
"MUTED": "ミュートされています",
|
"MUTED": "ミュートされています",
|
||||||
"MAX_VOLUME": "最大音量"
|
"MAX_VOLUME": "最大音量",
|
||||||
|
|
||||||
|
"RTC_MODE_OFF": "AEC 無効",
|
||||||
|
"RTC_MODE_ON": "AEC 有効"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,9 @@
|
|||||||
|
|
||||||
"VOLUME":"音量 ",
|
"VOLUME":"音量 ",
|
||||||
"MUTED":"已静音",
|
"MUTED":"已静音",
|
||||||
"MAX_VOLUME":"最大音量"
|
"MAX_VOLUME":"最大音量",
|
||||||
|
|
||||||
|
"RTC_MODE_OFF":"AEC 关闭",
|
||||||
|
"RTC_MODE_ON":"AEC 开启"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,9 @@
|
|||||||
|
|
||||||
"VOLUME": "音量 ",
|
"VOLUME": "音量 ",
|
||||||
"MUTED": "已靜音",
|
"MUTED": "已靜音",
|
||||||
"MAX_VOLUME": "最大音量"
|
"MAX_VOLUME": "最大音量",
|
||||||
|
|
||||||
|
"RTC_MODE_OFF": "AEC 關閉",
|
||||||
|
"RTC_MODE_ON": "AEC 開啟"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,27 +26,26 @@ void AfeAudioProcessor::Initialize(AudioCodec* codec) {
|
|||||||
char* ns_model_name = esp_srmodel_filter(models, ESP_NSNET_PREFIX, NULL);
|
char* ns_model_name = esp_srmodel_filter(models, ESP_NSNET_PREFIX, NULL);
|
||||||
|
|
||||||
afe_config_t* afe_config = afe_config_init(input_format.c_str(), NULL, AFE_TYPE_VC, AFE_MODE_HIGH_PERF);
|
afe_config_t* afe_config = afe_config_init(input_format.c_str(), NULL, AFE_TYPE_VC, AFE_MODE_HIGH_PERF);
|
||||||
#ifdef CONFIG_USE_DEVICE_AEC
|
|
||||||
afe_config->aec_init = true;
|
|
||||||
afe_config->aec_mode = AEC_MODE_VOIP_HIGH_PERF;
|
afe_config->aec_mode = AEC_MODE_VOIP_HIGH_PERF;
|
||||||
#else
|
afe_config->vad_mode = VAD_MODE_0;
|
||||||
afe_config->aec_init = false;
|
afe_config->vad_min_noise_ms = 100;
|
||||||
#endif
|
|
||||||
afe_config->ns_init = true;
|
afe_config->ns_init = true;
|
||||||
afe_config->ns_model_name = ns_model_name;
|
afe_config->ns_model_name = ns_model_name;
|
||||||
afe_config->afe_ns_mode = AFE_NS_MODE_NET;
|
afe_config->afe_ns_mode = AFE_NS_MODE_NET;
|
||||||
#ifdef CONFIG_USE_DEVICE_AEC
|
|
||||||
afe_config->vad_init = false;
|
|
||||||
#else
|
|
||||||
afe_config->vad_init = true;
|
|
||||||
afe_config->vad_mode = VAD_MODE_0;
|
|
||||||
afe_config->vad_min_noise_ms = 100;
|
|
||||||
#endif
|
|
||||||
afe_config->afe_perferred_core = 1;
|
afe_config->afe_perferred_core = 1;
|
||||||
afe_config->afe_perferred_priority = 1;
|
afe_config->afe_perferred_priority = 1;
|
||||||
afe_config->agc_init = false;
|
afe_config->agc_init = false;
|
||||||
afe_config->memory_alloc_mode = AFE_MEMORY_ALLOC_MORE_PSRAM;
|
afe_config->memory_alloc_mode = AFE_MEMORY_ALLOC_MORE_PSRAM;
|
||||||
|
|
||||||
|
#ifdef CONFIG_USE_DEVICE_AEC
|
||||||
|
afe_config->aec_init = true;
|
||||||
|
afe_config->vad_init = false;
|
||||||
|
#else
|
||||||
|
afe_config->aec_init = false;
|
||||||
|
afe_config->vad_init = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
afe_iface_ = esp_afe_handle_from_config(afe_config);
|
afe_iface_ = esp_afe_handle_from_config(afe_config);
|
||||||
afe_data_ = afe_iface_->create_from_config(afe_config);
|
afe_data_ = afe_iface_->create_from_config(afe_config);
|
||||||
|
|
||||||
@ -137,3 +136,17 @@ void AfeAudioProcessor::AudioProcessorTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AfeAudioProcessor::EnableDeviceAec(bool enable) {
|
||||||
|
if (enable) {
|
||||||
|
#if CONFIG_USE_DEVICE_AEC
|
||||||
|
afe_iface_->disable_vad(afe_data_);
|
||||||
|
afe_iface_->enable_aec(afe_data_);
|
||||||
|
#else
|
||||||
|
ESP_LOGE(TAG, "Device AEC is not supported");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
afe_iface_->disable_aec(afe_data_);
|
||||||
|
afe_iface_->enable_vad(afe_data_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ public:
|
|||||||
void OnOutput(std::function<void(std::vector<int16_t>&& data)> callback) override;
|
void OnOutput(std::function<void(std::vector<int16_t>&& data)> callback) override;
|
||||||
void OnVadStateChange(std::function<void(bool speaking)> callback) override;
|
void OnVadStateChange(std::function<void(bool speaking)> callback) override;
|
||||||
size_t GetFeedSize() override;
|
size_t GetFeedSize() override;
|
||||||
|
void EnableDeviceAec(bool enable) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventGroupHandle_t event_group_ = nullptr;
|
EventGroupHandle_t event_group_ = nullptr;
|
||||||
|
|||||||
@ -19,6 +19,7 @@ public:
|
|||||||
virtual void OnOutput(std::function<void(std::vector<int16_t>&& data)> callback) = 0;
|
virtual void OnOutput(std::function<void(std::vector<int16_t>&& data)> callback) = 0;
|
||||||
virtual void OnVadStateChange(std::function<void(bool speaking)> callback) = 0;
|
virtual void OnVadStateChange(std::function<void(bool speaking)> callback) = 0;
|
||||||
virtual size_t GetFeedSize() = 0;
|
virtual size_t GetFeedSize() = 0;
|
||||||
|
virtual void EnableDeviceAec(bool enable) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -42,3 +42,9 @@ size_t DummyAudioProcessor::GetFeedSize() {
|
|||||||
// 返回一个固定的帧大小,比如 30ms 的数据
|
// 返回一个固定的帧大小,比如 30ms 的数据
|
||||||
return 30 * codec_->input_sample_rate() / 1000;
|
return 30 * codec_->input_sample_rate() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DummyAudioProcessor::EnableDeviceAec(bool enable) {
|
||||||
|
if (enable) {
|
||||||
|
ESP_LOGE(TAG, "Device AEC is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ public:
|
|||||||
void OnOutput(std::function<void(std::vector<int16_t>&& data)> callback) override;
|
void OnOutput(std::function<void(std::vector<int16_t>&& data)> callback) override;
|
||||||
void OnVadStateChange(std::function<void(bool speaking)> callback) override;
|
void OnVadStateChange(std::function<void(bool speaking)> callback) override;
|
||||||
size_t GetFeedSize() override;
|
size_t GetFeedSize() override;
|
||||||
|
void EnableDeviceAec(bool enable) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioCodec* codec_ = nullptr;
|
AudioCodec* codec_ = nullptr;
|
||||||
|
|||||||
@ -48,4 +48,8 @@
|
|||||||
#define DISPLAY_MIRROR_X true
|
#define DISPLAY_MIRROR_X true
|
||||||
#define DISPLAY_MIRROR_Y true
|
#define DISPLAY_MIRROR_Y true
|
||||||
|
|
||||||
|
|
||||||
|
// A MCP Test: Control a lamp
|
||||||
|
#define LAMP_GPIO GPIO_NUM_18
|
||||||
|
|
||||||
#endif // _BOARD_CONFIG_H_
|
#endif // _BOARD_CONFIG_H_
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "mcp_server.h"
|
||||||
|
#include "lamp_controller.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
#include "display/oled_display.h"
|
#include "display/oled_display.h"
|
||||||
@ -133,9 +135,13 @@ private:
|
|||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 物联网初始化,添加对 AI 可见设备
|
||||||
void InitializeIot() {
|
void InitializeIot() {
|
||||||
|
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
||||||
|
#elif CONFIG_IOT_PROTOCOL_MCP
|
||||||
|
static LampController lamp(LAMP_GPIO);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "mcp_server.h"
|
||||||
|
#include "lamp_controller.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
#include "assets/lang_config.h"
|
#include "assets/lang_config.h"
|
||||||
@ -154,9 +156,13 @@ private:
|
|||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 物联网初始化,添加对 AI 可见设备
|
||||||
void InitializeIot() {
|
void InitializeIot() {
|
||||||
|
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
||||||
|
#elif CONFIG_IOT_PROTOCOL_MCP
|
||||||
|
static LampController lamp(LAMP_GPIO);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -53,4 +53,7 @@
|
|||||||
#define ML307_TX_PIN GPIO_NUM_12
|
#define ML307_TX_PIN GPIO_NUM_12
|
||||||
|
|
||||||
|
|
||||||
|
// A MCP Test: Control a lamp
|
||||||
|
#define LAMP_GPIO GPIO_NUM_18
|
||||||
|
|
||||||
#endif // _BOARD_CONFIG_H_
|
#endif // _BOARD_CONFIG_H_
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "mcp_server.h"
|
||||||
|
#include "lamp_controller.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
|
|
||||||
@ -149,10 +151,14 @@ private:
|
|||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 物联网初始化,添加对 AI 可见设备
|
||||||
void InitializeIot() {
|
void InitializeIot() {
|
||||||
|
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
thing_manager.AddThing(iot::CreateThing("Screen"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
||||||
|
#elif CONFIG_IOT_PROTOCOL_MCP
|
||||||
|
static LampController lamp(LAMP_GPIO);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -282,4 +282,8 @@
|
|||||||
#define DISPLAY_SPI_MODE 0
|
#define DISPLAY_SPI_MODE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// A MCP Test: Control a lamp
|
||||||
|
#define LAMP_GPIO GPIO_NUM_18
|
||||||
|
|
||||||
#endif // _BOARD_CONFIG_H_
|
#endif // _BOARD_CONFIG_H_
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "mcp_server.h"
|
||||||
|
#include "lamp_controller.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
#include "assets/lang_config.h"
|
#include "assets/lang_config.h"
|
||||||
@ -150,11 +152,15 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 物联网初始化,逐步迁移到 MCP 协议
|
||||||
void InitializeIot() {
|
void InitializeIot() {
|
||||||
|
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
||||||
|
#elif CONFIG_IOT_PROTOCOL_MCP
|
||||||
|
static LampController lamp(LAMP_GPIO);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -52,4 +52,8 @@
|
|||||||
#define DISPLAY_MIRROR_X true
|
#define DISPLAY_MIRROR_X true
|
||||||
#define DISPLAY_MIRROR_Y true
|
#define DISPLAY_MIRROR_Y true
|
||||||
|
|
||||||
|
|
||||||
|
// A MCP Test: Control a lamp
|
||||||
|
#define LAMP_GPIO GPIO_NUM_18
|
||||||
|
|
||||||
#endif // _BOARD_CONFIG_H_
|
#endif // _BOARD_CONFIG_H_
|
||||||
|
|||||||
44
main/boards/common/lamp_controller.h
Normal file
44
main/boards/common/lamp_controller.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef __LAMP_CONTROLLER_H__
|
||||||
|
#define __LAMP_CONTROLLER_H__
|
||||||
|
|
||||||
|
#include "mcp_server.h"
|
||||||
|
|
||||||
|
|
||||||
|
class LampController {
|
||||||
|
private:
|
||||||
|
bool power_ = false;
|
||||||
|
gpio_num_t gpio_num_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LampController(gpio_num_t gpio_num) : gpio_num_(gpio_num) {
|
||||||
|
gpio_config_t config = {
|
||||||
|
.pin_bit_mask = (1ULL << gpio_num_),
|
||||||
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = GPIO_INTR_DISABLE,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(gpio_config(&config));
|
||||||
|
gpio_set_level(gpio_num_, 0);
|
||||||
|
|
||||||
|
auto& mcp_server = McpServer::GetInstance();
|
||||||
|
mcp_server.AddTool("self.lamp.get_state", "Get the power state of the lamp", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
return power_ ? "{\"power\": true}" : "{\"power\": false}";
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.lamp.turn_on", "Turn on the lamp", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
power_ = true;
|
||||||
|
gpio_set_level(gpio_num_, 1);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.lamp.turn_off", "Turn off the lamp", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
power_ = false;
|
||||||
|
gpio_set_level(gpio_num_, 0);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __LAMP_CONTROLLER_H__
|
||||||
@ -203,6 +203,9 @@ std::string WifiBoard::GetDeviceStatusJson() {
|
|||||||
* "type": "wifi",
|
* "type": "wifi",
|
||||||
* "ssid": "Xiaozhi",
|
* "ssid": "Xiaozhi",
|
||||||
* "rssi": -60
|
* "rssi": -60
|
||||||
|
* },
|
||||||
|
* "chip": {
|
||||||
|
* "temperature": 25
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
@ -255,6 +258,14 @@ std::string WifiBoard::GetDeviceStatusJson() {
|
|||||||
}
|
}
|
||||||
cJSON_AddItemToObject(root, "network", network);
|
cJSON_AddItemToObject(root, "network", network);
|
||||||
|
|
||||||
|
// Chip
|
||||||
|
float esp32temp = 0.0f;
|
||||||
|
if (board.GetTemperature(esp32temp)) {
|
||||||
|
auto chip = cJSON_CreateObject();
|
||||||
|
cJSON_AddNumberToObject(chip, "temperature", esp32temp);
|
||||||
|
cJSON_AddItemToObject(root, "chip", chip);
|
||||||
|
}
|
||||||
|
|
||||||
auto json_str = cJSON_PrintUnformatted(root);
|
auto json_str = cJSON_PrintUnformatted(root);
|
||||||
std::string json(json_str);
|
std::string json(json_str);
|
||||||
cJSON_free(json_str);
|
cJSON_free(json_str);
|
||||||
|
|||||||
@ -82,6 +82,15 @@ private:
|
|||||||
}
|
}
|
||||||
app.ToggleChatState();
|
app.ToggleChatState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if CONFIG_USE_DEVICE_AEC
|
||||||
|
boot_button_.OnDoubleClick([this]() {
|
||||||
|
auto& app = Application::GetInstance();
|
||||||
|
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||||
|
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeIli9341Display() {
|
void InitializeIli9341Display() {
|
||||||
|
|||||||
@ -82,6 +82,15 @@ private:
|
|||||||
}
|
}
|
||||||
app.ToggleChatState();
|
app.ToggleChatState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if CONFIG_USE_DEVICE_AEC
|
||||||
|
boot_button_.OnDoubleClick([this]() {
|
||||||
|
auto& app = Application::GetInstance();
|
||||||
|
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||||
|
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeIli9341Display() {
|
void InitializeIli9341Display() {
|
||||||
|
|||||||
@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
ESP-SparkBot 的底座
|
|
||||||
https://gitee.com/esp-friends/esp_sparkbot/tree/master/example/tank/c2_tracked_chassis
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "iot/thing.h"
|
|
||||||
#include "board.h"
|
|
||||||
|
|
||||||
#include <driver/gpio.h>
|
|
||||||
#include <driver/uart.h>
|
|
||||||
#include <esp_log.h>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "boards/esp-sparkbot/config.h"
|
|
||||||
|
|
||||||
#define TAG "Chassis"
|
|
||||||
|
|
||||||
namespace iot {
|
|
||||||
|
|
||||||
class Chassis : public Thing {
|
|
||||||
private:
|
|
||||||
light_mode_t light_mode_ = LIGHT_MODE_ALWAYS_ON;
|
|
||||||
|
|
||||||
void SendUartMessage(const char * command_str) {
|
|
||||||
uint8_t len = strlen(command_str);
|
|
||||||
uart_write_bytes(ECHO_UART_PORT_NUM, command_str, len);
|
|
||||||
ESP_LOGI(TAG, "Sent command: %s", command_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeEchoUart() {
|
|
||||||
uart_config_t uart_config = {
|
|
||||||
.baud_rate = ECHO_UART_BAUD_RATE,
|
|
||||||
.data_bits = UART_DATA_8_BITS,
|
|
||||||
.parity = UART_PARITY_DISABLE,
|
|
||||||
.stop_bits = UART_STOP_BITS_1,
|
|
||||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
|
||||||
.source_clk = UART_SCLK_DEFAULT,
|
|
||||||
};
|
|
||||||
int intr_alloc_flags = 0;
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
|
||||||
ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));
|
|
||||||
ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, UART_ECHO_TXD, UART_ECHO_RXD, UART_ECHO_RTS, UART_ECHO_CTS));
|
|
||||||
|
|
||||||
SendUartMessage("w2");
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Chassis() : Thing("Chassis", "小机器人的底座:有履带可以移动;可以调整灯光效果"), light_mode_(LIGHT_MODE_ALWAYS_ON) {
|
|
||||||
InitializeEchoUart();
|
|
||||||
|
|
||||||
// 定义设备的属性
|
|
||||||
properties_.AddNumberProperty("light_mode", "灯光效果编号", [this]() -> int {
|
|
||||||
return (light_mode_ - 2 <= 0) ? 1 : light_mode_ - 2;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 定义设备可以被远程执行的指令
|
|
||||||
methods_.AddMethod("GoForward", "向前走", ParameterList(), [this](const ParameterList& parameters) {
|
|
||||||
SendUartMessage("x0.0 y1.0");
|
|
||||||
});
|
|
||||||
|
|
||||||
methods_.AddMethod("GoBack", "向后退", ParameterList(), [this](const ParameterList& parameters) {
|
|
||||||
SendUartMessage("x0.0 y-1.0");
|
|
||||||
});
|
|
||||||
|
|
||||||
methods_.AddMethod("TurnLeft", "向左转", ParameterList(), [this](const ParameterList& parameters) {
|
|
||||||
SendUartMessage("x-1.0 y0.0");
|
|
||||||
});
|
|
||||||
|
|
||||||
methods_.AddMethod("TurnRight", "向右转", ParameterList(), [this](const ParameterList& parameters) {
|
|
||||||
SendUartMessage("x1.0 y0.0");
|
|
||||||
});
|
|
||||||
|
|
||||||
methods_.AddMethod("Dance", "跳舞", ParameterList(), [this](const ParameterList& parameters) {
|
|
||||||
SendUartMessage("d1");
|
|
||||||
light_mode_ = LIGHT_MODE_MAX;
|
|
||||||
});
|
|
||||||
|
|
||||||
methods_.AddMethod("SwitchLightMode", "打开灯", ParameterList({
|
|
||||||
Parameter("lightmode", "1到6之间的整数", kValueTypeNumber, true)
|
|
||||||
}), [this](const ParameterList& parameters) {
|
|
||||||
char command_str[5] = {'w', 0, 0};
|
|
||||||
char mode = static_cast<char>(parameters["lightmode"].number()) + 2;
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Input Light Mode: %c", (mode + '0'));
|
|
||||||
|
|
||||||
if (mode >= 3 && mode <= 8) {
|
|
||||||
command_str[1] = mode + '0';
|
|
||||||
SendUartMessage(command_str);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace iot
|
|
||||||
|
|
||||||
DECLARE_THING(Chassis);
|
|
||||||
@ -5,13 +5,15 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "mcp_server.h"
|
||||||
|
|
||||||
#include <wifi_station.h>
|
#include <wifi_station.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <esp_lcd_panel_vendor.h>
|
#include <esp_lcd_panel_vendor.h>
|
||||||
#include <driver/i2c_master.h>
|
#include <driver/i2c_master.h>
|
||||||
#include <driver/spi_common.h>
|
#include <driver/spi_common.h>
|
||||||
|
#include <driver/uart.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "esp32_camera.h"
|
#include "esp32_camera.h"
|
||||||
|
|
||||||
@ -48,6 +50,7 @@ private:
|
|||||||
Button boot_button_;
|
Button boot_button_;
|
||||||
Display* display_;
|
Display* display_;
|
||||||
Esp32Camera* camera_;
|
Esp32Camera* camera_;
|
||||||
|
light_mode_t light_mode_ = LIGHT_MODE_ALWAYS_ON;
|
||||||
|
|
||||||
void InitializeI2c() {
|
void InitializeI2c() {
|
||||||
// Initialize I2C peripheral
|
// Initialize I2C peripheral
|
||||||
@ -132,8 +135,8 @@ private:
|
|||||||
camera_config.pin_reset = SPARKBOT_CAMERA_RESET;
|
camera_config.pin_reset = SPARKBOT_CAMERA_RESET;
|
||||||
camera_config.pin_xclk = SPARKBOT_CAMERA_XCLK;
|
camera_config.pin_xclk = SPARKBOT_CAMERA_XCLK;
|
||||||
camera_config.pin_pclk = SPARKBOT_CAMERA_PCLK;
|
camera_config.pin_pclk = SPARKBOT_CAMERA_PCLK;
|
||||||
camera_config.pin_sscb_sda = SPARKBOT_CAMERA_SIOD;
|
camera_config.pin_sccb_sda = SPARKBOT_CAMERA_SIOD;
|
||||||
camera_config.pin_sscb_scl = SPARKBOT_CAMERA_SIOC;
|
camera_config.pin_sccb_scl = SPARKBOT_CAMERA_SIOC;
|
||||||
|
|
||||||
camera_config.pin_d0 = SPARKBOT_CAMERA_D0;
|
camera_config.pin_d0 = SPARKBOT_CAMERA_D0;
|
||||||
camera_config.pin_d1 = SPARKBOT_CAMERA_D1;
|
camera_config.pin_d1 = SPARKBOT_CAMERA_D1;
|
||||||
@ -163,12 +166,86 @@ private:
|
|||||||
camera_ = new Esp32Camera(camera_config);
|
camera_ = new Esp32Camera(camera_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
/*
|
||||||
void InitializeIot() {
|
ESP-SparkBot 的底座
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
https://gitee.com/esp-friends/esp_sparkbot/tree/master/example/tank/c2_tracked_chassis
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
*/
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
void InitializeEchoUart() {
|
||||||
thing_manager.AddThing(iot::CreateThing("Chassis"));
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = ECHO_UART_BAUD_RATE,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
|
.source_clk = UART_SCLK_DEFAULT,
|
||||||
|
};
|
||||||
|
int intr_alloc_flags = 0;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
||||||
|
ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));
|
||||||
|
ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, UART_ECHO_TXD, UART_ECHO_RXD, UART_ECHO_RTS, UART_ECHO_CTS));
|
||||||
|
|
||||||
|
SendUartMessage("w2");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendUartMessage(const char * command_str) {
|
||||||
|
uint8_t len = strlen(command_str);
|
||||||
|
uart_write_bytes(ECHO_UART_PORT_NUM, command_str, len);
|
||||||
|
ESP_LOGI(TAG, "Sent command: %s", command_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeTools() {
|
||||||
|
auto& mcp_server = McpServer::GetInstance();
|
||||||
|
// 定义设备的属性
|
||||||
|
mcp_server.AddTool("self.chassis.get_light_mode", "获取灯光效果编号", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
if (light_mode_ < 2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return light_mode_ - 2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.chassis.go_forward", "前进", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
SendUartMessage("x0.0 y1.0");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.chassis.go_back", "后退", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
SendUartMessage("x0.0 y-1.0");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.chassis.turn_left", "向左转", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
SendUartMessage("x-1.0 y0.0");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.chassis.turn_right", "向右转", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
SendUartMessage("x1.0 y0.0");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.chassis.dance", "跳舞", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
SendUartMessage("d1");
|
||||||
|
light_mode_ = LIGHT_MODE_MAX;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mcp_server.AddTool("self.chassis.switch_light_mode", "打开灯光效果", PropertyList({
|
||||||
|
Property("light_mode", kPropertyTypeInteger, 1, 6)
|
||||||
|
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
char command_str[5] = {'w', 0, 0};
|
||||||
|
char mode = static_cast<light_mode_t>(properties["light_mode"].value<int>());
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Switch Light Mode: %c", (mode + '0'));
|
||||||
|
|
||||||
|
if (mode >= 3 && mode <= 8) {
|
||||||
|
command_str[1] = mode + '0';
|
||||||
|
SendUartMessage(command_str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Invalid light mode");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -177,8 +254,9 @@ public:
|
|||||||
InitializeSpi();
|
InitializeSpi();
|
||||||
InitializeDisplay();
|
InitializeDisplay();
|
||||||
InitializeButtons();
|
InitializeButtons();
|
||||||
InitializeIot();
|
|
||||||
InitializeCamera();
|
InitializeCamera();
|
||||||
|
InitializeEchoUart();
|
||||||
|
InitializeTools();
|
||||||
GetBacklight()->RestoreBrightness();
|
GetBacklight()->RestoreBrightness();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/timers.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
#include <esp_log.h>
|
|
||||||
|
|
||||||
#include "board.h"
|
|
||||||
#include "boards/common/wifi_board.h"
|
|
||||||
#include "boards/esp32-s3-touch-amoled-1.8/config.h"
|
|
||||||
#include "iot/thing.h"
|
|
||||||
|
|
||||||
#define TAG "BoardControl"
|
|
||||||
|
|
||||||
namespace iot {
|
|
||||||
|
|
||||||
class BoardControl : public Thing {
|
|
||||||
public:
|
|
||||||
BoardControl() : Thing("BoardControl", "当前 AI 机器人管理和控制") {
|
|
||||||
// 修改重新配网
|
|
||||||
methods_.AddMethod("ResetWifiConfiguration", "重新配网", ParameterList(),
|
|
||||||
[this](const ParameterList& parameters) {
|
|
||||||
ESP_LOGI(TAG, "ResetWifiConfiguration");
|
|
||||||
auto board = static_cast<WifiBoard*>(&Board::GetInstance());
|
|
||||||
if (board && board->GetBoardType() == "wifi") {
|
|
||||||
board->ResetWifiConfiguration();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace iot
|
|
||||||
|
|
||||||
DECLARE_THING(BoardControl);
|
|
||||||
@ -7,7 +7,7 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "mcp_server.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "power_save_timer.h"
|
#include "power_save_timer.h"
|
||||||
#include "axp2101.h"
|
#include "axp2101.h"
|
||||||
@ -288,13 +288,16 @@ private:
|
|||||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 初始化工具
|
||||||
void InitializeIot() {
|
void InitializeTools() {
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto &mcp_server = McpServer::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
"Reboot the device and enter WiFi configuration mode.\n"
|
||||||
thing_manager.AddThing(iot::CreateThing("Battery"));
|
"**CAUTION** You must ask the user to confirm this action.",
|
||||||
thing_manager.AddThing(iot::CreateThing("BoardControl"));
|
PropertyList(), [this](const PropertyList& properties) {
|
||||||
|
ResetWifiConfiguration();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -308,7 +311,7 @@ public:
|
|||||||
InitializeSH8601Display();
|
InitializeSH8601Display();
|
||||||
InitializeTouch();
|
InitializeTouch();
|
||||||
InitializeButtons();
|
InitializeButtons();
|
||||||
InitializeIot();
|
InitializeTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual AudioCodec* GetAudioCodec() override {
|
virtual AudioCodec* GetAudioCodec() override {
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/timers.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
#include <esp_log.h>
|
|
||||||
|
|
||||||
#include "board.h"
|
|
||||||
#include "boards/common/wifi_board.h"
|
|
||||||
#include "iot/thing.h"
|
|
||||||
|
|
||||||
#define TAG "BoardControl"
|
|
||||||
|
|
||||||
namespace iot {
|
|
||||||
|
|
||||||
class BoardControl : public Thing {
|
|
||||||
public:
|
|
||||||
BoardControl() : Thing("BoardControl", "当前 AI 机器人管理和控制") {
|
|
||||||
// 修改重新配网
|
|
||||||
methods_.AddMethod("ResetWifiConfiguration", "重新配网", ParameterList(),
|
|
||||||
[this](const ParameterList& parameters) {
|
|
||||||
ESP_LOGI(TAG, "ResetWifiConfiguration");
|
|
||||||
auto board = static_cast<WifiBoard*>(&Board::GetInstance());
|
|
||||||
if (board && board->GetBoardType() == "wifi") {
|
|
||||||
board->ResetWifiConfiguration();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace iot
|
|
||||||
|
|
||||||
DECLARE_THING(BoardControl);
|
|
||||||
@ -5,8 +5,7 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "mcp_server.h"
|
||||||
|
|
||||||
|
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include "i2c_device.h"
|
#include "i2c_device.h"
|
||||||
@ -233,13 +232,16 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 初始化工具
|
||||||
void InitializeIot() {
|
void InitializeTools() {
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto &mcp_server = McpServer::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
"Reboot the device and enter WiFi configuration mode.\n"
|
||||||
thing_manager.AddThing(iot::CreateThing("Battery"));
|
"**CAUTION** You must ask the user to confirm this action.",
|
||||||
thing_manager.AddThing(iot::CreateThing("BoardControl"));
|
PropertyList(), [this](const PropertyList& properties) {
|
||||||
|
ResetWifiConfiguration();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -257,7 +259,7 @@ public:
|
|||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
InitializeButtons();
|
InitializeButtons();
|
||||||
InitializeIot();
|
InitializeTools();
|
||||||
GetBacklight()->RestoreBrightness();
|
GetBacklight()->RestoreBrightness();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -140,6 +140,15 @@ private:
|
|||||||
}
|
}
|
||||||
app.ToggleChatState();
|
app.ToggleChatState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if CONFIG_USE_DEVICE_AEC
|
||||||
|
boot_button_.OnDoubleClick([this]() {
|
||||||
|
auto& app = Application::GetInstance();
|
||||||
|
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||||
|
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeIli9341Display() {
|
void InitializeIli9341Display() {
|
||||||
|
|||||||
@ -224,7 +224,6 @@ private:
|
|||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
thing_manager.AddThing(iot::CreateThing("Screen"));
|
||||||
// thing_manager.AddThing(iot::CreateThing("Lamp"));
|
|
||||||
thing_manager.AddThing(iot::CreateThing("Battery"));
|
thing_manager.AddThing(iot::CreateThing("Battery"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "iot/thing_manager.h"
|
|
||||||
#include "led/circular_strip.h"
|
#include "led/circular_strip.h"
|
||||||
#include "led_strip_control.h"
|
#include "led_strip_control.h"
|
||||||
|
|
||||||
@ -54,12 +53,8 @@ private:
|
|||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 物联网初始化,添加对 AI 可见设备
|
||||||
void InitializeIot() {
|
void InitializeIot() {
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
|
||||||
|
|
||||||
led_strip_ = new CircularStrip(BUILTIN_LED_GPIO, 8);
|
led_strip_ = new CircularStrip(BUILTIN_LED_GPIO, 8);
|
||||||
auto led_strip_control = new LedStripControl(led_strip_);
|
new LedStripControl(led_strip_);
|
||||||
thing_manager.AddThing(led_strip_control);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "led_strip_control.h"
|
#include "led_strip_control.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "mcp_server.h"
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
|
|
||||||
#define TAG "LedStripControl"
|
#define TAG "LedStripControl"
|
||||||
@ -22,102 +23,108 @@ StripColor LedStripControl::RGBToColor(int red, int green, int blue) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LedStripControl::LedStripControl(CircularStrip* led_strip)
|
LedStripControl::LedStripControl(CircularStrip* led_strip)
|
||||||
: Thing("LedStripControl", "LED 灯带控制,一共有8个灯珠"), led_strip_(led_strip) {
|
: led_strip_(led_strip) {
|
||||||
// 从设置中读取亮度等级
|
// 从设置中读取亮度等级
|
||||||
Settings settings("led_strip");
|
Settings settings("led_strip");
|
||||||
brightness_level_ = settings.GetInt("brightness", 4); // 默认等级4
|
brightness_level_ = settings.GetInt("brightness", 4); // 默认等级4
|
||||||
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
||||||
|
|
||||||
// 定义设备的属性
|
auto& mcp_server = McpServer::GetInstance();
|
||||||
properties_.AddNumberProperty("brightness", "对话时的亮度等级(0-8)", [this]() -> int {
|
mcp_server.AddTool("self.led_strip.get_brightness",
|
||||||
return brightness_level_;
|
"Get the brightness of the led strip (0-8)",
|
||||||
});
|
PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
return brightness_level_;
|
||||||
|
});
|
||||||
|
|
||||||
// 定义设备可以被远程执行的指令
|
mcp_server.AddTool("self.led_strip.set_brightness",
|
||||||
methods_.AddMethod("SetBrightness", "设置对话时的亮度等级", ParameterList({
|
"Set the brightness of the led strip (0-8)",
|
||||||
Parameter("level", "亮度等级(0-8)", kValueTypeNumber, true)
|
PropertyList({
|
||||||
}), [this](const ParameterList& parameters) {
|
Property("level", kPropertyTypeInteger, 0, 8)
|
||||||
int level = static_cast<int>(parameters["level"].number());
|
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
ESP_LOGI(TAG, "Set LedStrip brightness level to %d", level);
|
int level = properties["level"].value<int>();
|
||||||
|
ESP_LOGI(TAG, "Set LedStrip brightness level to %d", level);
|
||||||
|
brightness_level_ = level;
|
||||||
|
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
||||||
|
|
||||||
if (level < 0) level = 0;
|
// 保存设置
|
||||||
if (level > 8) level = 8;
|
Settings settings("led_strip", true);
|
||||||
|
settings.SetInt("brightness", brightness_level_);
|
||||||
|
|
||||||
brightness_level_ = level;
|
return true;
|
||||||
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
});
|
||||||
|
|
||||||
// 保存设置
|
mcp_server.AddTool("self.led_strip.set_single_color",
|
||||||
Settings settings("led_strip", true);
|
"Set the color of a single led.",
|
||||||
settings.SetInt("brightness", brightness_level_);
|
PropertyList({
|
||||||
});
|
Property("index", kPropertyTypeInteger, 0, 7),
|
||||||
|
Property("red", kPropertyTypeInteger, 0, 255),
|
||||||
|
Property("green", kPropertyTypeInteger, 0, 255),
|
||||||
|
Property("blue", kPropertyTypeInteger, 0, 255)
|
||||||
|
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
int index = properties["index"].value<int>();
|
||||||
|
int red = properties["red"].value<int>();
|
||||||
|
int green = properties["green"].value<int>();
|
||||||
|
int blue = properties["blue"].value<int>();
|
||||||
|
ESP_LOGI(TAG, "Set led strip single color %d to %d, %d, %d",
|
||||||
|
index, red, green, blue);
|
||||||
|
led_strip_->SetSingleColor(index, RGBToColor(red, green, blue));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
methods_.AddMethod("SetSingleColor", "设置单个灯颜色", ParameterList({
|
mcp_server.AddTool("self.led_strip.set_all_color",
|
||||||
Parameter("index", "灯珠索引(0-7)", kValueTypeNumber, true),
|
"Set the color of all leds.",
|
||||||
Parameter("red", "红色(0-255)", kValueTypeNumber, true),
|
PropertyList({
|
||||||
Parameter("green", "绿色(0-255)", kValueTypeNumber, true),
|
Property("red", kPropertyTypeInteger, 0, 255),
|
||||||
Parameter("blue", "蓝色(0-255)", kValueTypeNumber, true)
|
Property("green", kPropertyTypeInteger, 0, 255),
|
||||||
}), [this](const ParameterList& parameters) {
|
Property("blue", kPropertyTypeInteger, 0, 255)
|
||||||
int index = parameters["index"].number();
|
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
StripColor color = RGBToColor(
|
int red = properties["red"].value<int>();
|
||||||
parameters["red"].number(),
|
int green = properties["green"].value<int>();
|
||||||
parameters["green"].number(),
|
int blue = properties["blue"].value<int>();
|
||||||
parameters["blue"].number()
|
ESP_LOGI(TAG, "Set led strip all color to %d, %d, %d",
|
||||||
);
|
red, green, blue);
|
||||||
ESP_LOGI(TAG, "Set led strip single color %d to %d, %d, %d",
|
led_strip_->SetAllColor(RGBToColor(red, green, blue));
|
||||||
index, color.red, color.green, color.blue);
|
return true;
|
||||||
led_strip_->SetSingleColor(index, color);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
methods_.AddMethod("SetAllColor", "设置所有灯颜色", ParameterList({
|
mcp_server.AddTool("self.led_strip.blink",
|
||||||
Parameter("red", "红色(0-255)", kValueTypeNumber, true),
|
"Blink the led strip. (闪烁)",
|
||||||
Parameter("green", "绿色(0-255)", kValueTypeNumber, true),
|
PropertyList({
|
||||||
Parameter("blue", "蓝色(0-255)", kValueTypeNumber, true)
|
Property("red", kPropertyTypeInteger, 0, 255),
|
||||||
}), [this](const ParameterList& parameters) {
|
Property("green", kPropertyTypeInteger, 0, 255),
|
||||||
StripColor color = RGBToColor(
|
Property("blue", kPropertyTypeInteger, 0, 255),
|
||||||
parameters["red"].number(),
|
Property("interval", kPropertyTypeInteger, 0, 1000)
|
||||||
parameters["green"].number(),
|
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
parameters["blue"].number()
|
int red = properties["red"].value<int>();
|
||||||
);
|
int green = properties["green"].value<int>();
|
||||||
ESP_LOGI(TAG, "Set led strip color to %d, %d, %d",
|
int blue = properties["blue"].value<int>();
|
||||||
color.red, color.green, color.blue
|
int interval = properties["interval"].value<int>();
|
||||||
);
|
ESP_LOGI(TAG, "Blink led strip with color %d, %d, %d, interval %dms",
|
||||||
led_strip_->SetAllColor(color);
|
red, green, blue, interval);
|
||||||
});
|
led_strip_->Blink(RGBToColor(red, green, blue), interval);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
methods_.AddMethod("Blink", "闪烁动画", ParameterList({
|
mcp_server.AddTool("self.led_strip.scroll",
|
||||||
Parameter("red", "红色(0-255)", kValueTypeNumber, true),
|
"Scroll the led strip. (跑马灯)",
|
||||||
Parameter("green", "绿色(0-255)", kValueTypeNumber, true),
|
PropertyList({
|
||||||
Parameter("blue", "蓝色(0-255)", kValueTypeNumber, true),
|
Property("red", kPropertyTypeInteger, 0, 255),
|
||||||
Parameter("interval", "间隔(ms)", kValueTypeNumber, true)
|
Property("green", kPropertyTypeInteger, 0, 255),
|
||||||
}), [this](const ParameterList& parameters) {
|
Property("blue", kPropertyTypeInteger, 0, 255),
|
||||||
int interval = parameters["interval"].number();
|
Property("length", kPropertyTypeInteger, 1, 7),
|
||||||
StripColor color = RGBToColor(
|
Property("interval", kPropertyTypeInteger, 0, 1000)
|
||||||
parameters["red"].number(),
|
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||||
parameters["green"].number(),
|
int red = properties["red"].value<int>();
|
||||||
parameters["blue"].number()
|
int green = properties["green"].value<int>();
|
||||||
);
|
int blue = properties["blue"].value<int>();
|
||||||
ESP_LOGI(TAG, "Blink led strip with color %d, %d, %d, interval %dms",
|
int interval = properties["interval"].value<int>();
|
||||||
color.red, color.green, color.blue, interval);
|
int length = properties["length"].value<int>();
|
||||||
led_strip_->Blink(color, interval);
|
ESP_LOGI(TAG, "Scroll led strip with color %d, %d, %d, length %d, interval %dms",
|
||||||
});
|
red, green, blue, length, interval);
|
||||||
|
StripColor low = RGBToColor(4, 4, 4);
|
||||||
|
StripColor high = RGBToColor(red, green, blue);
|
||||||
|
led_strip_->Scroll(low, high, length, interval);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
methods_.AddMethod("Scroll", "跑马灯动画", ParameterList({
|
|
||||||
Parameter("red", "红色(0-255)", kValueTypeNumber, true),
|
|
||||||
Parameter("green", "绿色(0-255)", kValueTypeNumber, true),
|
|
||||||
Parameter("blue", "蓝色(0-255)", kValueTypeNumber, true),
|
|
||||||
Parameter("length", "滚动条长度(1-7)", kValueTypeNumber, true),
|
|
||||||
Parameter("interval", "间隔(ms)", kValueTypeNumber, true)
|
|
||||||
}), [this](const ParameterList& parameters) {
|
|
||||||
int interval = parameters["interval"].number();
|
|
||||||
int length = parameters["length"].number();
|
|
||||||
StripColor low = RGBToColor(4, 4, 4);
|
|
||||||
StripColor high = RGBToColor(
|
|
||||||
parameters["red"].number(),
|
|
||||||
parameters["green"].number(),
|
|
||||||
parameters["blue"].number()
|
|
||||||
);
|
|
||||||
ESP_LOGI(TAG, "Scroll led strip with color %d, %d, %d, length %d, interval %dms",
|
|
||||||
high.red, high.green, high.blue, length, interval);
|
|
||||||
led_strip_->Scroll(low, high, length, interval);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
#ifndef LED_STRIP_CONTROL_H
|
#ifndef LED_STRIP_CONTROL_H
|
||||||
#define LED_STRIP_CONTROL_H
|
#define LED_STRIP_CONTROL_H
|
||||||
|
|
||||||
#include "iot/thing.h"
|
|
||||||
#include "led/circular_strip.h"
|
#include "led/circular_strip.h"
|
||||||
|
|
||||||
using namespace iot;
|
class LedStripControl {
|
||||||
|
|
||||||
class LedStripControl : public Thing {
|
|
||||||
private:
|
private:
|
||||||
CircularStrip* led_strip_;
|
CircularStrip* led_strip_;
|
||||||
int brightness_level_; // 亮度等级 (0-8)
|
int brightness_level_; // 亮度等级 (0-8)
|
||||||
|
|||||||
@ -116,6 +116,15 @@ private:
|
|||||||
}
|
}
|
||||||
app.ToggleChatState();
|
app.ToggleChatState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if CONFIG_USE_DEVICE_AEC
|
||||||
|
boot_button_.OnDoubleClick([this]() {
|
||||||
|
auto& app = Application::GetInstance();
|
||||||
|
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||||
|
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeSt7789Display() {
|
void InitializeSt7789Display() {
|
||||||
|
|||||||
@ -40,4 +40,8 @@
|
|||||||
#define DISPLAY_OFFSET_Y 0
|
#define DISPLAY_OFFSET_Y 0
|
||||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||||
|
|
||||||
|
|
||||||
|
// A MCP Test: Control a lamp
|
||||||
|
#define LAMP_GPIO GPIO_NUM_18
|
||||||
|
|
||||||
#endif // _BOARD_CONFIG_H_
|
#endif // _BOARD_CONFIG_H_
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "power_save_timer.h"
|
#include "power_save_timer.h"
|
||||||
|
#include "mcp_server.h"
|
||||||
|
#include "lamp_controller.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
#include "assets/lang_config.h"
|
#include "assets/lang_config.h"
|
||||||
@ -195,11 +197,15 @@ private:
|
|||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 物联网初始化,添加对 AI 可见设备
|
||||||
void InitializeIot() {
|
void InitializeIot() {
|
||||||
|
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
thing_manager.AddThing(iot::CreateThing("Screen"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
thing_manager.AddThing(iot::CreateThing("Lamp"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Battery"));
|
thing_manager.AddThing(iot::CreateThing("Battery"));
|
||||||
|
#elif CONFIG_IOT_PROTOCOL_MCP
|
||||||
|
static LampController lamp(LAMP_GPIO);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/timers.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
#include <esp_log.h>
|
|
||||||
|
|
||||||
#include "board.h"
|
|
||||||
#include "boards/common/wifi_board.h"
|
|
||||||
#include "boards/waveshare-s3-touch-amoled-1.75/config.h"
|
|
||||||
#include "iot/thing.h"
|
|
||||||
|
|
||||||
#define TAG "BoardControl"
|
|
||||||
|
|
||||||
namespace iot {
|
|
||||||
|
|
||||||
class BoardControl : public Thing {
|
|
||||||
public:
|
|
||||||
BoardControl() : Thing("BoardControl", "当前 AI 机器人管理和控制") {
|
|
||||||
// 修改重新配网
|
|
||||||
methods_.AddMethod("ResetWifiConfiguration", "重新配网", ParameterList(),
|
|
||||||
[this](const ParameterList& parameters) {
|
|
||||||
ESP_LOGI(TAG, "ResetWifiConfiguration");
|
|
||||||
auto board = static_cast<WifiBoard*>(&Board::GetInstance());
|
|
||||||
if (board && board->GetBoardType() == "wifi") {
|
|
||||||
board->ResetWifiConfiguration();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace iot
|
|
||||||
|
|
||||||
DECLARE_THING(BoardControl);
|
|
||||||
@ -7,7 +7,7 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "mcp_server.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "power_save_timer.h"
|
#include "power_save_timer.h"
|
||||||
#include "axp2101.h"
|
#include "axp2101.h"
|
||||||
@ -221,7 +221,17 @@ private:
|
|||||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||||
ResetWifiConfiguration();
|
ResetWifiConfiguration();
|
||||||
}
|
}
|
||||||
app.ToggleChatState(); });
|
app.ToggleChatState();
|
||||||
|
});
|
||||||
|
|
||||||
|
#if CONFIG_USE_DEVICE_AEC
|
||||||
|
boot_button_.OnDoubleClick([this]() {
|
||||||
|
auto& app = Application::GetInstance();
|
||||||
|
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||||
|
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeSH8601Display() {
|
void InitializeSH8601Display() {
|
||||||
@ -294,13 +304,16 @@ private:
|
|||||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
// 初始化工具
|
||||||
void InitializeIot() {
|
void InitializeTools() {
|
||||||
auto &thing_manager = iot::ThingManager::GetInstance();
|
auto &mcp_server = McpServer::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
"Reboot the device and enter WiFi configuration mode.\n"
|
||||||
thing_manager.AddThing(iot::CreateThing("Battery"));
|
"**CAUTION** You must ask the user to confirm this action.",
|
||||||
thing_manager.AddThing(iot::CreateThing("BoardControl"));
|
PropertyList(), [this](const PropertyList& properties) {
|
||||||
|
ResetWifiConfiguration();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -313,7 +326,7 @@ public:
|
|||||||
InitializeSH8601Display();
|
InitializeSH8601Display();
|
||||||
InitializeTouch();
|
InitializeTouch();
|
||||||
InitializeButtons();
|
InitializeButtons();
|
||||||
InitializeIot();
|
InitializeTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual AudioCodec* GetAudioCodec() override {
|
virtual AudioCodec* GetAudioCodec() override {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "led/single_led.h"
|
#include "led/single_led.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "mcp_server.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "power_save_timer.h"
|
#include "power_save_timer.h"
|
||||||
@ -142,14 +142,32 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 物联网初始化,添加对 AI 可见设备
|
void InitializeTools() {
|
||||||
void InitializeIot() {
|
|
||||||
Settings settings("vendor");
|
Settings settings("vendor");
|
||||||
press_to_talk_enabled_ = settings.GetInt("press_to_talk", 0) != 0;
|
press_to_talk_enabled_ = settings.GetInt("press_to_talk", 0) != 0;
|
||||||
|
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
#error "XiaoZhi 协议不支持"
|
||||||
thing_manager.AddThing(iot::CreateThing("PressToTalk"));
|
#elif CONFIG_IOT_PROTOCOL_MCP
|
||||||
|
auto& mcp_server = McpServer::GetInstance();
|
||||||
|
mcp_server.AddTool("self.set_press_to_talk",
|
||||||
|
"Switch between press to talk mode (长按说话) and click to talk mode (单击说话).\n"
|
||||||
|
"The mode can be `press_to_talk` or `click_to_talk`.",
|
||||||
|
PropertyList({
|
||||||
|
Property("mode", kPropertyTypeString)
|
||||||
|
}),
|
||||||
|
[this](const PropertyList& properties) -> ReturnValue {
|
||||||
|
auto mode = properties["mode"].value<std::string>();
|
||||||
|
if (mode == "press_to_talk") {
|
||||||
|
SetPressToTalkEnabled(true);
|
||||||
|
return true;
|
||||||
|
} else if (mode == "click_to_talk") {
|
||||||
|
SetPressToTalkEnabled(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Invalid mode: " + mode);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -161,7 +179,7 @@ public:
|
|||||||
InitializeSsd1306Display();
|
InitializeSsd1306Display();
|
||||||
InitializeButtons();
|
InitializeButtons();
|
||||||
InitializePowerSaveTimer();
|
InitializePowerSaveTimer();
|
||||||
InitializeIot();
|
InitializeTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Led* GetLed() override {
|
virtual Led* GetLed() override {
|
||||||
@ -194,30 +212,3 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_BOARD(XminiC3Board);
|
DECLARE_BOARD(XminiC3Board);
|
||||||
|
|
||||||
|
|
||||||
namespace iot {
|
|
||||||
|
|
||||||
class PressToTalk : public Thing {
|
|
||||||
public:
|
|
||||||
PressToTalk() : Thing("PressToTalk", "控制对话模式,一种是长按对话,一种是单击后连续对话。") {
|
|
||||||
// 定义设备的属性
|
|
||||||
properties_.AddBooleanProperty("enabled", "true 表示长按说话模式,false 表示单击说话模式", []() -> bool {
|
|
||||||
auto board = static_cast<XminiC3Board*>(&Board::GetInstance());
|
|
||||||
return board->IsPressToTalkEnabled();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 定义设备可以被远程执行的指令
|
|
||||||
methods_.AddMethod("SetEnabled", "启用或禁用长按说话模式,调用前需要经过用户确认", ParameterList({
|
|
||||||
Parameter("enabled", "true 表示长按说话模式,false 表示单击说话模式", kValueTypeBoolean, true)
|
|
||||||
}), [](const ParameterList& parameters) {
|
|
||||||
bool enabled = parameters["enabled"].boolean();
|
|
||||||
auto board = static_cast<XminiC3Board*>(&Board::GetInstance());
|
|
||||||
board->SetPressToTalkEnabled(enabled);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace iot
|
|
||||||
|
|
||||||
DECLARE_THING(PressToTalk);
|
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
#include "iot/thing.h"
|
|
||||||
#include "board.h"
|
|
||||||
|
|
||||||
#include <esp_log.h>
|
|
||||||
|
|
||||||
#define TAG "Temperature"
|
|
||||||
|
|
||||||
namespace iot {
|
|
||||||
|
|
||||||
class Temperature : public Thing {
|
|
||||||
private:
|
|
||||||
float esp32temp = 0.0f;
|
|
||||||
public:
|
|
||||||
Temperature() : Thing("Temperature", "芯片温度管理") {
|
|
||||||
// 定义设备的属性
|
|
||||||
properties_.AddNumberProperty("temp", "当前芯片温度", [this]() -> float {
|
|
||||||
auto& board = Board::GetInstance();
|
|
||||||
if (board.GetTemperature(esp32temp)) {
|
|
||||||
return esp32temp;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace iot
|
|
||||||
|
|
||||||
DECLARE_THING(Temperature);
|
|
||||||
@ -180,10 +180,12 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InitializeIot() {
|
void InitializeIot() {
|
||||||
|
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
thing_manager.AddThing(iot::CreateThing("Speaker"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Screen"));
|
thing_manager.AddThing(iot::CreateThing("Screen"));
|
||||||
thing_manager.AddThing(iot::CreateThing("Battery"));
|
thing_manager.AddThing(iot::CreateThing("Battery"));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
#define TAG "MCP"
|
#define TAG "MCP"
|
||||||
|
|
||||||
McpServer::McpServer() {
|
McpServer::McpServer() {
|
||||||
AddCommonTools();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
McpServer::~McpServer() {
|
McpServer::~McpServer() {
|
||||||
@ -27,6 +26,10 @@ McpServer::~McpServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void McpServer::AddCommonTools() {
|
void McpServer::AddCommonTools() {
|
||||||
|
// To speed up the response time, we add the common tools to the beginning of
|
||||||
|
// the tools list to utilize the prompt cache.
|
||||||
|
// Backup the original tools list and restore it after adding the common tools.
|
||||||
|
auto original_tools = std::move(tools_);
|
||||||
auto& board = Board::GetInstance();
|
auto& board = Board::GetInstance();
|
||||||
|
|
||||||
AddTool("self.get_device_status",
|
AddTool("self.get_device_status",
|
||||||
@ -96,9 +99,18 @@ void McpServer::AddCommonTools() {
|
|||||||
return camera->Explain(question);
|
return camera->Explain(question);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore the original tools list to the end of the tools list
|
||||||
|
tools_.insert(tools_.end(), original_tools.begin(), original_tools.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void McpServer::AddTool(McpTool* tool) {
|
void McpServer::AddTool(McpTool* tool) {
|
||||||
|
// Prevent adding duplicate tools
|
||||||
|
if (std::find_if(tools_.begin(), tools_.end(), [tool](const McpTool* t) { return t->name() == tool->name(); }) != tools_.end()) {
|
||||||
|
ESP_LOGW(TAG, "Tool %s already added", tool->name().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Add tool: %s", tool->name().c_str());
|
ESP_LOGI(TAG, "Add tool: %s", tool->name().c_str());
|
||||||
tools_.push_back(tool);
|
tools_.push_back(tool);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -255,6 +255,7 @@ public:
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddCommonTools();
|
||||||
void AddTool(McpTool* tool);
|
void AddTool(McpTool* tool);
|
||||||
void AddTool(const std::string& name, const std::string& description, const PropertyList& properties, std::function<ReturnValue(const PropertyList&)> callback);
|
void AddTool(const std::string& name, const std::string& description, const PropertyList& properties, std::function<ReturnValue(const PropertyList&)> callback);
|
||||||
void ParseMessage(const cJSON* json);
|
void ParseMessage(const cJSON* json);
|
||||||
@ -264,7 +265,6 @@ private:
|
|||||||
McpServer();
|
McpServer();
|
||||||
~McpServer();
|
~McpServer();
|
||||||
|
|
||||||
void AddCommonTools();
|
|
||||||
void ParseCapabilities(const cJSON* capabilities);
|
void ParseCapabilities(const cJSON* capabilities);
|
||||||
|
|
||||||
void ReplyResult(int id, const std::string& result);
|
void ReplyResult(int id, const std::string& result);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user