Update to 2.0.1

This commit is contained in:
2025-09-15 22:04:01 +08:00
parent 5c43129024
commit 7d7f5eae3d
74 changed files with 5253 additions and 439 deletions

559
main/timer_manager.cc Normal file
View File

@@ -0,0 +1,559 @@
#include "timer_manager.h"
#include <esp_log.h>
#include <esp_timer.h>
#include <cstring>
#include <sstream>
const char* TimerManager::TAG = "TimerManager";
TimerManager::TimerManager() : is_running_(false) {
ESP_LOGI(TAG, "TimerManager initialized");
}
TimerManager::~TimerManager() {
StopManager();
ESP_LOGI(TAG, "TimerManager destroyed");
}
std::string TimerManager::CreateCountdownTimer(const std::string& name,
uint32_t duration_ms,
const std::string& description) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
TimerTask task;
task.id = GenerateTaskId();
task.name = name;
task.type = TimerType::COUNTDOWN;
task.status = TimerStatus::PENDING;
task.duration_ms = duration_ms;
task.description = description;
task.created_time = time(nullptr);
tasks_[task.id] = task;
ESP_LOGI(TAG, "Created countdown timer: %s (ID: %s, Duration: %u ms)",
name.c_str(), task.id.c_str(), duration_ms);
return task.id;
}
std::string TimerManager::CreateDelayedMcpTask(const std::string& name,
uint32_t delay_ms,
const std::string& mcp_tool_name,
const std::string& mcp_tool_args,
const std::string& description) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
TimerTask task;
task.id = GenerateTaskId();
task.name = name;
task.type = TimerType::DELAYED_EXEC;
task.status = TimerStatus::PENDING;
task.duration_ms = delay_ms;
task.mcp_tool_name = mcp_tool_name;
task.mcp_tool_args = mcp_tool_args;
task.description = description;
task.created_time = time(nullptr);
tasks_[task.id] = task;
ESP_LOGI(TAG, "Created delayed MCP task: %s (ID: %s, Delay: %u ms, Tool: %s)",
name.c_str(), task.id.c_str(), delay_ms, mcp_tool_name.c_str());
return task.id;
}
std::string TimerManager::CreatePeriodicTask(const std::string& name,
uint32_t interval_ms,
int repeat_count,
const std::string& mcp_tool_name,
const std::string& mcp_tool_args,
const std::string& description) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
TimerTask task;
task.id = GenerateTaskId();
task.name = name;
task.type = TimerType::PERIODIC;
task.status = TimerStatus::PENDING;
task.interval_ms = interval_ms;
task.repeat_count = repeat_count;
task.current_repeat = 0;
task.mcp_tool_name = mcp_tool_name;
task.mcp_tool_args = mcp_tool_args;
task.description = description;
task.created_time = time(nullptr);
tasks_[task.id] = task;
ESP_LOGI(TAG, "Created periodic task: %s (ID: %s, Interval: %u ms, Repeat: %d)",
name.c_str(), task.id.c_str(), interval_ms, repeat_count);
return task.id;
}
std::string TimerManager::CreateScheduledTask(const std::string& name,
time_t scheduled_time,
const std::string& mcp_tool_name,
const std::string& mcp_tool_args,
const std::string& description) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
TimerTask task;
task.id = GenerateTaskId();
task.name = name;
task.type = TimerType::SCHEDULED;
task.status = TimerStatus::PENDING;
task.scheduled_time = scheduled_time;
task.mcp_tool_name = mcp_tool_name;
task.mcp_tool_args = mcp_tool_args;
task.description = description;
task.created_time = time(nullptr);
tasks_[task.id] = task;
ESP_LOGI(TAG, "Created scheduled task: %s (ID: %s, Time: %ld)",
name.c_str(), task.id.c_str(), scheduled_time);
return task.id;
}
bool TimerManager::StartTask(const std::string& task_id) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
auto it = tasks_.find(task_id);
if (it == tasks_.end()) {
ESP_LOGE(TAG, "Task not found: %s", task_id.c_str());
return false;
}
TimerTask& task = it->second;
if (task.status != TimerStatus::PENDING) {
ESP_LOGW(TAG, "Task %s is not in pending status", task_id.c_str());
return false;
}
// 创建FreeRTOS定时器
TimerHandle_t timer_handle = xTimerCreate(
task.name.c_str(),
pdMS_TO_TICKS(task.duration_ms),
(task.type == TimerType::PERIODIC) ? pdTRUE : pdFALSE,
(void*)task_id.c_str(),
TimerCallback
);
if (timer_handle == nullptr) {
ESP_LOGE(TAG, "Failed to create timer for task: %s", task_id.c_str());
return false;
}
timers_[task_id] = timer_handle;
task.status = TimerStatus::RUNNING;
task.start_time = time(nullptr);
if (xTimerStart(timer_handle, 0) != pdPASS) {
ESP_LOGE(TAG, "Failed to start timer for task: %s", task_id.c_str());
xTimerDelete(timer_handle, 0);
timers_.erase(task_id);
task.status = TimerStatus::FAILED;
return false;
}
ESP_LOGI(TAG, "Started task: %s", task_id.c_str());
return true;
}
bool TimerManager::StopTask(const std::string& task_id) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
auto it = tasks_.find(task_id);
if (it == tasks_.end()) {
ESP_LOGE(TAG, "Task not found: %s", task_id.c_str());
return false;
}
TimerTask& task = it->second;
if (task.status != TimerStatus::RUNNING) {
ESP_LOGW(TAG, "Task %s is not running", task_id.c_str());
return false;
}
auto timer_it = timers_.find(task_id);
if (timer_it != timers_.end()) {
xTimerStop(timer_it->second, 0);
xTimerDelete(timer_it->second, 0);
timers_.erase(timer_it);
}
task.status = TimerStatus::CANCELLED;
task.end_time = time(nullptr);
ESP_LOGI(TAG, "Stopped task: %s", task_id.c_str());
return true;
}
bool TimerManager::CancelTask(const std::string& task_id) {
return StopTask(task_id);
}
bool TimerManager::DeleteTask(const std::string& task_id) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
// 先停止任务
StopTask(task_id);
auto it = tasks_.find(task_id);
if (it == tasks_.end()) {
ESP_LOGE(TAG, "Task not found: %s", task_id.c_str());
return false;
}
tasks_.erase(it);
ESP_LOGI(TAG, "Deleted task: %s", task_id.c_str());
return true;
}
TimerTask* TimerManager::GetTask(const std::string& task_id) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
auto it = tasks_.find(task_id);
if (it == tasks_.end()) {
return nullptr;
}
return &it->second;
}
std::vector<TimerTask> TimerManager::GetAllTasks() {
std::lock_guard<std::mutex> lock(tasks_mutex_);
std::vector<TimerTask> result;
for (const auto& pair : tasks_) {
result.push_back(pair.second);
}
return result;
}
std::vector<TimerTask> TimerManager::GetTasksByStatus(TimerStatus status) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
std::vector<TimerTask> result;
for (const auto& pair : tasks_) {
if (pair.second.status == status) {
result.push_back(pair.second);
}
}
return result;
}
std::vector<TimerTask> TimerManager::GetRunningTasks() {
return GetTasksByStatus(TimerStatus::RUNNING);
}
std::vector<TimerTask> TimerManager::GetUpcomingTasks(int minutes) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
std::vector<TimerTask> result;
time_t now = time(nullptr);
time_t future_time = now + (minutes * 60);
for (const auto& pair : tasks_) {
const TimerTask& task = pair.second;
if (task.status == TimerStatus::PENDING &&
task.scheduled_time >= now &&
task.scheduled_time <= future_time) {
result.push_back(task);
}
}
return result;
}
int TimerManager::GetTaskCount() {
std::lock_guard<std::mutex> lock(tasks_mutex_);
return tasks_.size();
}
int TimerManager::GetTaskCountByStatus(TimerStatus status) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
int count = 0;
for (const auto& pair : tasks_) {
if (pair.second.status == status) {
count++;
}
}
return count;
}
int TimerManager::GetTaskCountByType(TimerType type) {
std::lock_guard<std::mutex> lock(tasks_mutex_);
int count = 0;
for (const auto& pair : tasks_) {
if (pair.second.type == type) {
count++;
}
}
return count;
}
void TimerManager::StartManager() {
if (is_running_) {
ESP_LOGW(TAG, "TimerManager is already running");
return;
}
is_running_ = true;
worker_thread_ = std::thread(&TimerManager::TaskWorker, this);
ESP_LOGI(TAG, "TimerManager started");
}
void TimerManager::StopManager() {
if (!is_running_) {
return;
}
is_running_ = false;
if (worker_thread_.joinable()) {
worker_thread_.join();
}
// 停止所有定时器
std::lock_guard<std::mutex> lock(tasks_mutex_);
for (auto& pair : timers_) {
xTimerStop(pair.second, 0);
xTimerDelete(pair.second, 0);
}
timers_.clear();
ESP_LOGI(TAG, "TimerManager stopped");
}
bool TimerManager::IsRunning() {
return is_running_;
}
void TimerManager::SetTaskCompletedCallback(std::function<void(const TimerTask&)> callback) {
task_completed_callback_ = callback;
}
void TimerManager::SetTaskFailedCallback(std::function<void(const TimerTask&, const std::string&)> callback) {
task_failed_callback_ = callback;
}
bool TimerManager::SaveToStorage() {
// TODO: 实现数据持久化到NVS或SPIFFS
ESP_LOGW(TAG, "SaveToStorage not implemented yet");
return true;
}
bool TimerManager::LoadFromStorage() {
// TODO: 实现从NVS或SPIFFS加载数据
ESP_LOGW(TAG, "LoadFromStorage not implemented yet");
return true;
}
std::string TimerManager::ExportToJson() {
std::lock_guard<std::mutex> lock(tasks_mutex_);
std::stringstream json;
json << "{\"tasks\":[";
bool first = true;
for (const auto& pair : tasks_) {
if (!first) json << ",";
first = false;
const TimerTask& task = pair.second;
json << "{"
<< "\"id\":\"" << task.id << "\","
<< "\"name\":\"" << task.name << "\","
<< "\"description\":\"" << task.description << "\","
<< "\"duration_ms\":" << task.duration_ms << ","
<< "\"interval_ms\":" << task.interval_ms << ","
<< "\"repeat_count\":" << task.repeat_count << ","
<< "\"current_repeat\":" << task.current_repeat << ","
<< "\"created_time\":" << task.created_time << ","
<< "\"start_time\":" << task.start_time << ","
<< "\"end_time\":" << task.end_time << ","
<< "\"scheduled_time\":" << task.scheduled_time << ","
<< "\"mcp_tool_name\":\"" << task.mcp_tool_name << "\","
<< "\"mcp_tool_args\":\"" << task.mcp_tool_args << "\","
<< "\"user_data\":\"" << task.user_data << "\",";
std::string status_str;
switch (task.status) {
case TimerStatus::PENDING: status_str = "pending"; break;
case TimerStatus::RUNNING: status_str = "running"; break;
case TimerStatus::COMPLETED: status_str = "completed"; break;
case TimerStatus::CANCELLED: status_str = "cancelled"; break;
case TimerStatus::FAILED: status_str = "failed"; break;
}
json << "\"status\":\"" << status_str << "\",";
std::string type_str;
switch (task.type) {
case TimerType::COUNTDOWN: type_str = "countdown"; break;
case TimerType::DELAYED_EXEC: type_str = "delayed_exec"; break;
case TimerType::PERIODIC: type_str = "periodic"; break;
case TimerType::SCHEDULED: type_str = "scheduled"; break;
}
json << "\"type\":\"" << type_str << "\"";
json << "}";
}
json << "]}";
return json.str();
}
std::string TimerManager::GenerateTaskId() {
static int counter = 0;
return "task_" + std::to_string(++counter) + "_" + std::to_string(time(nullptr));
}
void TimerManager::TaskWorker() {
ESP_LOGI(TAG, "Task worker thread started");
while (is_running_) {
vTaskDelay(pdMS_TO_TICKS(1000));
// 检查定时任务
std::lock_guard<std::mutex> lock(tasks_mutex_);
time_t now = time(nullptr);
for (auto& pair : tasks_) {
TimerTask& task = pair.second;
if (task.status == TimerStatus::PENDING &&
task.type == TimerType::SCHEDULED &&
now >= task.scheduled_time) {
ESP_LOGI(TAG, "Executing scheduled task: %s", task.id.c_str());
ExecuteTask(task);
}
}
}
ESP_LOGI(TAG, "Task worker thread stopped");
}
void TimerManager::ExecuteTask(TimerTask& task) {
task.status = TimerStatus::RUNNING;
task.start_time = time(nullptr);
bool success = true;
std::string error_msg;
try {
if (!task.mcp_tool_name.empty()) {
success = ExecuteMcpTool(task.mcp_tool_name, task.mcp_tool_args);
if (!success) {
error_msg = "MCP tool execution failed";
}
}
} catch (const std::exception& e) {
success = false;
error_msg = e.what();
} catch (...) {
success = false;
error_msg = "Unknown error occurred";
}
task.end_time = time(nullptr);
if (success) {
if (task.type == TimerType::PERIODIC) {
task.current_repeat++;
if (task.repeat_count == -1 || task.current_repeat < task.repeat_count) {
// 继续下一次重复
task.status = TimerStatus::PENDING;
ESP_LOGI(TAG, "Periodic task %s completed repeat %d/%d",
task.id.c_str(), task.current_repeat, task.repeat_count);
} else {
// 所有重复完成
task.status = TimerStatus::COMPLETED;
ESP_LOGI(TAG, "Periodic task %s completed all repeats", task.id.c_str());
NotifyTaskCompleted(task);
}
} else {
task.status = TimerStatus::COMPLETED;
ESP_LOGI(TAG, "Task %s completed successfully", task.id.c_str());
NotifyTaskCompleted(task);
}
} else {
task.status = TimerStatus::FAILED;
ESP_LOGE(TAG, "Task %s failed: %s", task.id.c_str(), error_msg.c_str());
NotifyTaskFailed(task, error_msg);
}
}
bool TimerManager::ExecuteMcpTool(const std::string& tool_name, const std::string& args) {
// TODO: 实现MCP工具执行
ESP_LOGW(TAG, "ExecuteMcpTool not implemented yet: %s with args: %s",
tool_name.c_str(), args.c_str());
return true;
}
void TimerManager::UpdateTaskStatus(TimerTask& task, TimerStatus status) {
task.status = status;
if (status == TimerStatus::RUNNING) {
task.start_time = time(nullptr);
} else if (status == TimerStatus::COMPLETED || status == TimerStatus::FAILED) {
task.end_time = time(nullptr);
}
}
void TimerManager::NotifyTaskCompleted(const TimerTask& task) {
if (task_completed_callback_) {
task_completed_callback_(task);
}
}
void TimerManager::NotifyTaskFailed(const TimerTask& task, const std::string& error) {
if (task_failed_callback_) {
task_failed_callback_(task, error);
}
}
void TimerManager::TimerCallback(TimerHandle_t timer_handle) {
const char* task_id = (const char*)pvTimerGetTimerID(timer_handle);
ESP_LOGI(TAG, "Timer callback triggered for task: %s", task_id);
// 获取任务管理器实例
TimerManager& manager = TimerManager::GetInstance();
std::lock_guard<std::mutex> lock(manager.tasks_mutex_);
auto it = manager.tasks_.find(task_id);
if (it != manager.tasks_.end()) {
TimerTask& task = it->second;
if (task.type == TimerType::COUNTDOWN) {
// 倒计时完成
task.status = TimerStatus::COMPLETED;
task.end_time = time(nullptr);
ESP_LOGI(TAG, "Countdown timer %s completed", task_id);
manager.NotifyTaskCompleted(task);
} else if (task.type == TimerType::DELAYED_EXEC) {
// 延时执行MCP工具
manager.ExecuteTask(task);
}
}
// 删除一次性定时器
if (xTimerIsTimerActive(timer_handle) == pdFALSE) {
xTimerDelete(timer_handle, 0);
manager.timers_.erase(task_id);
}
}