feat: ESP-Hi 改用 MCP 协议 (#740)

* feat(esp-hi): use MCP protocol

* docs(esp-hi): Add README

* feat(esp-hi): remove redundant checks and add option to disable WebUI
This commit is contained in:
laride
2025-06-03 16:45:03 +08:00
committed by GitHub
parent 9122664f0f
commit bfc695b1ee
6 changed files with 208 additions and 258 deletions

View File

@@ -3,7 +3,7 @@
#include "application.h"
#include "button.h"
#include "config.h"
#include "iot/thing_manager.h"
#include "mcp_server.h"
#include <wifi_station.h>
#include <esp_log.h>
#include <driver/i2c_master.h>
@@ -21,8 +21,14 @@
#include "anim_player.h"
#include "emoji_display.h"
#include "servo_dog_ctrl.h"
#include "led_strip.h"
#include "driver/rmt_tx.h"
#include "sdkconfig.h"
#ifdef CONFIG_ESP_HI_WEB_CONTROL_ENABLED
#include "esp_hi_web_control.h"
#endif //CONFIG_ESP_HI_WEB_CONTROL_ENABLED
#define TAG "ESP_HI"
@@ -47,6 +53,23 @@ static const ili9341_lcd_init_cmd_t vendor_specific_init[] = {
{0x2C, NULL, 0, 0}, // Memory write
};
static const led_strip_config_t bsp_strip_config = {
.strip_gpio_num = GPIO_NUM_8,
.max_leds = 4,
.led_model = LED_MODEL_WS2812,
.flags = {
.invert_out = false
}
};
static const led_strip_rmt_config_t bsp_rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10 * 1000 * 1000,
.flags = {
.with_dma = false
}
};
class EspHi : public WifiBoard {
private:
Button boot_button_;
@@ -54,7 +77,10 @@ private:
Button move_wake_button_;
anim::EmojiWidget* display_ = nullptr;
bool web_server_initialized_ = false;
led_strip_handle_t led_strip_;
bool led_on_ = false;
#ifdef CONFIG_ESP_HI_WEB_CONTROL_ENABLED
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
@@ -72,6 +98,7 @@ private:
}
}
}
#endif //CONFIG_ESP_HI_WEB_CONTROL_ENABLED
void HandleMoveWakePressDown(int64_t current_time, int64_t &last_trigger_time, int &gesture_state)
{
@@ -154,17 +181,39 @@ private:
HandleMoveWakePressUp(current_time, last_trigger_time, gesture_state);
});
}
void InitializeLed() {
ESP_LOGI(TAG, "BLINK_GPIO setting %d", bsp_strip_config.strip_gpio_num);
ESP_ERROR_CHECK(led_strip_new_rmt_device(&bsp_strip_config, &bsp_rmt_config, &led_strip_));
led_strip_set_pixel(led_strip_, 0, 0x00, 0x00, 0x00);
led_strip_set_pixel(led_strip_, 1, 0x00, 0x00, 0x00);
led_strip_set_pixel(led_strip_, 2, 0x00, 0x00, 0x00);
led_strip_set_pixel(led_strip_, 3, 0x00, 0x00, 0x00);
led_strip_refresh(led_strip_);
}
esp_err_t SetLedColor(uint8_t r, uint8_t g, uint8_t b) {
esp_err_t ret = ESP_OK;
ret |= led_strip_set_pixel(led_strip_, 0, r, g, b);
ret |= led_strip_set_pixel(led_strip_, 1, r, g, b);
ret |= led_strip_set_pixel(led_strip_, 2, r, g, b);
ret |= led_strip_set_pixel(led_strip_, 3, r, g, b);
ret |= led_strip_refresh(led_strip_);
return ret;
}
void InitializeIot()
{
ESP_LOGI(TAG, "Initialize Iot");
auto &thing_manager = iot::ThingManager::GetInstance();
thing_manager.AddThing(iot::CreateThing("DogLight"));
thing_manager.AddThing(iot::CreateThing("DogAction_basic"));
thing_manager.AddThing(iot::CreateThing("DogAction_extra"));
InitializeLed();
SetLedColor(0x00, 0x00, 0x00);
#ifdef CONFIG_ESP_HI_WEB_CONTROL_ENABLED
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
&wifi_event_handler, this));
#endif //CONFIG_ESP_HI_WEB_CONTROL_ENABLED
}
void InitializeSpi()
@@ -235,6 +284,107 @@ private:
#endif
}
void InitializeTools()
{
auto& mcp_server = McpServer::GetInstance();
// 基础动作控制
mcp_server.AddTool("self.dog.forward", "机器人向前移动", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_FORWARD, NULL);
return true;
});
mcp_server.AddTool("self.dog.backward", "机器人向后移动", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_BACKWARD, NULL);
return true;
});
mcp_server.AddTool("self.dog.sway_back_forth", "机器人做前后摇摆动作", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_SWAY_BACK_FORTH, NULL);
return true;
});
mcp_server.AddTool("self.dog.turn_left", "机器人向左转", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_TURN_LEFT, NULL);
return true;
});
mcp_server.AddTool("self.dog.turn_right", "机器人向右转", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_TURN_RIGHT, NULL);
return true;
});
mcp_server.AddTool("self.dog.lay_down", "机器人趴下", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_LAY_DOWN, NULL);
return true;
});
mcp_server.AddTool("self.dog.sway", "机器人做左右摇摆动作", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
dog_action_args_t args = {
.repeat_count = 4,
};
servo_dog_ctrl_send(DOG_STATE_SWAY, &args);
return true;
});
// 扩展动作控制
mcp_server.AddTool("self.dog.retract_legs", "机器人收回腿部", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_RETRACT_LEGS, NULL);
return true;
});
mcp_server.AddTool("self.dog.stop", "立即停止机器人当前动作", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_IDLE, NULL);
return true;
});
mcp_server.AddTool("self.dog.shake_hand", "机器人做握手动作", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_SHAKE_HAND, NULL);
return true;
});
mcp_server.AddTool("self.dog.shake_back_legs", "机器人伸懒腰", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_SHAKE_BACK_LEGS, NULL);
return true;
});
mcp_server.AddTool("self.dog.jump_forward", "机器人向前跳跃", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
servo_dog_ctrl_send(DOG_STATE_JUMP_FORWARD, NULL);
return true;
});
// 灯光控制
mcp_server.AddTool("self.light.get_power", "获取灯是否打开", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
return led_on_;
});
mcp_server.AddTool("self.light.turn_on", "打开灯", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
SetLedColor(0xFF, 0xFF, 0xFF);
led_on_ = true;
return true;
});
mcp_server.AddTool("self.light.turn_off", "关闭灯", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
SetLedColor(0x00, 0x00, 0x00);
led_on_ = false;
return true;
});
mcp_server.AddTool("self.light.set_rgb", "设置RGB颜色", PropertyList({
Property("r", kPropertyTypeInteger, 0, 255),
Property("g", kPropertyTypeInteger, 0, 255),
Property("b", kPropertyTypeInteger, 0, 255)
}), [this](const PropertyList& properties) -> ReturnValue {
int r = properties["r"].value<int>();
int g = properties["g"].value<int>();
int b = properties["b"].value<int>();
led_on_ = true;
SetLedColor(r, g, b);
return true;
});
}
public:
EspHi() : boot_button_(BOOT_BUTTON_GPIO),
audio_wake_button_(AUDIO_WAKE_BUTTON_GPIO),
@@ -244,6 +394,7 @@ public:
InitializeIot();
InitializeSpi();
InitializeLcdDisplay();
InitializeTools();
}
virtual AudioCodec* GetAudioCodec() override