#include "alarm_manager.h" #include #include #include #include #include #include #include #include #define TAG "AlarmManager" #define ALARM_SETTINGS_NAMESPACE "alarms" AlarmManager::AlarmManager() : initialized_(false), next_alarm_id_(1), default_snooze_minutes_(5), default_max_snooze_count_(3) { } AlarmManager::~AlarmManager() { Cleanup(); } void AlarmManager::Initialize() { if (initialized_) { return; } ESP_LOGI(TAG, "Initializing Alarm Manager"); // 初始化设置存储 settings_ = std::make_unique(ALARM_SETTINGS_NAMESPACE, true); // 从存储中加载闹钟 LoadAlarmsFromStorage(); // 获取下一个闹钟ID next_alarm_id_ = settings_->GetInt("next_id", 1); initialized_ = true; ESP_LOGI(TAG, "Alarm Manager initialized with %d alarms", alarms_.size()); } void AlarmManager::Cleanup() { if (!initialized_) { return; } ESP_LOGI(TAG, "Cleaning up Alarm Manager"); // 停止所有活动的闹钟 StopAllActiveAlarms(); // 保存数据 SaveAlarmsToStorage(); // 清理资源 { std::lock_guard lock(alarms_mutex_); alarms_.clear(); } settings_.reset(); initialized_ = false; } int AlarmManager::AddAlarm(int hour, int minute, AlarmRepeatMode repeat_mode, const std::string& label, const std::string& music_name) { if (!initialized_) { ESP_LOGE(TAG, "AlarmManager not initialized"); return -1; } if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { ESP_LOGE(TAG, "Invalid time: %02d:%02d", hour, minute); return -1; } std::lock_guard lock(alarms_mutex_); auto alarm = std::make_unique(); alarm->id = GetNextAlarmId(); alarm->hour = hour; alarm->minute = minute; alarm->repeat_mode = repeat_mode; alarm->label = label; alarm->music_name = music_name; alarm->status = kAlarmEnabled; alarm->snooze_minutes = default_snooze_minutes_; alarm->max_snooze_count = default_max_snooze_count_; // 设置星期掩码 switch (repeat_mode) { case kAlarmDaily: alarm->weekdays_mask = 0b1111111; // 每天 break; case kAlarmWeekdays: alarm->weekdays_mask = 0b0111110; // 周一到周五 break; case kAlarmWeekends: alarm->weekdays_mask = 0b1000001; // 周六周日 break; default: alarm->weekdays_mask = 0; // 一次性或自定义 break; } int alarm_id = alarm->id; alarms_.push_back(std::move(alarm)); // 保存到存储 SaveAlarmToStorage(*alarms_.back()); settings_->SetInt("next_id", next_alarm_id_); ESP_LOGI(TAG, "Added alarm %d: %02d:%02d, repeat=%d, label='%s', music='%s'", alarm_id, hour, minute, repeat_mode, label.c_str(), music_name.c_str()); return alarm_id; } bool AlarmManager::RemoveAlarm(int alarm_id) { if (!initialized_) { return false; } std::lock_guard lock(alarms_mutex_); auto it = std::find_if(alarms_.begin(), alarms_.end(), [alarm_id](const auto& alarm) { return alarm->id == alarm_id; }); if (it != alarms_.end()) { ESP_LOGI(TAG, "Removing alarm %d", alarm_id); alarms_.erase(it); RemoveAlarmFromStorage(alarm_id); return true; } ESP_LOGW(TAG, "Alarm %d not found for removal", alarm_id); return false; } bool AlarmManager::EnableAlarm(int alarm_id, bool enabled) { if (!initialized_) { return false; } std::lock_guard lock(alarms_mutex_); auto it = std::find_if(alarms_.begin(), alarms_.end(), [alarm_id](const auto& alarm) { return alarm->id == alarm_id; }); if (it != alarms_.end()) { (*it)->status = enabled ? kAlarmEnabled : kAlarmDisabled; SaveAlarmToStorage(**it); ESP_LOGI(TAG, "Alarm %d %s", alarm_id, enabled ? "enabled" : "disabled"); return true; } return false; } bool AlarmManager::ModifyAlarm(int alarm_id, int hour, int minute, AlarmRepeatMode repeat_mode, const std::string& label, const std::string& music_name) { if (!initialized_) { return false; } if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { ESP_LOGE(TAG, "Invalid time: %02d:%02d", hour, minute); return false; } std::lock_guard lock(alarms_mutex_); auto it = std::find_if(alarms_.begin(), alarms_.end(), [alarm_id](const auto& alarm) { return alarm->id == alarm_id; }); if (it != alarms_.end()) { (*it)->hour = hour; (*it)->minute = minute; (*it)->repeat_mode = repeat_mode; (*it)->label = label; (*it)->music_name = music_name; // 重新设置星期掩码 switch (repeat_mode) { case kAlarmDaily: (*it)->weekdays_mask = 0b1111111; break; case kAlarmWeekdays: (*it)->weekdays_mask = 0b0111110; break; case kAlarmWeekends: (*it)->weekdays_mask = 0b1000001; break; default: break; } SaveAlarmToStorage(**it); ESP_LOGI(TAG, "Modified alarm %d: %02d:%02d", alarm_id, hour, minute); return true; } return false; } std::vector AlarmManager::GetAllAlarms() const { if (!initialized_) { return {}; } std::lock_guard lock(alarms_mutex_); std::vector result; for (const auto& alarm : alarms_) { result.push_back(*alarm); } return result; } AlarmItem* AlarmManager::GetAlarm(int alarm_id) { if (!initialized_) { return nullptr; } std::lock_guard lock(alarms_mutex_); auto it = std::find_if(alarms_.begin(), alarms_.end(), [alarm_id](const auto& alarm) { return alarm->id == alarm_id; }); return (it != alarms_.end()) ? it->get() : nullptr; } std::vector AlarmManager::GetActiveAlarms() const { if (!initialized_) { return {}; } std::lock_guard lock(alarms_mutex_); std::vector result; for (const auto& alarm : alarms_) { if (alarm->status == kAlarmTriggered || alarm->status == kAlarmSnoozed) { result.push_back(*alarm); } } return result; } std::string AlarmManager::GetNextAlarmInfo() const { if (!initialized_) { return "闹钟管理器未初始化"; } std::lock_guard lock(alarms_mutex_); // 查找下一个要触发的闹钟 AlarmItem* next_alarm = nullptr; int64_t current_time = GetCurrentTimeInMinutes(); int current_weekday = GetCurrentWeekday(); int64_t min_time_diff = 24 * 60 * 7; // 一周的分钟数 for (const auto& alarm : alarms_) { if (alarm->status != kAlarmEnabled) { continue; } // 计算今天和明天的时间差 int64_t alarm_time = alarm->hour * 60 + alarm->minute; for (int day_offset = 0; day_offset < 7; day_offset++) { int check_weekday = (current_weekday + day_offset) % 7; if (day_offset == 0 && alarm_time <= current_time) { continue; // 今天已经过了 } if (alarm->repeat_mode == kAlarmOnce && day_offset > 0) { continue; // 一次性闹钟只检查今天 } if (IsWeekdayActive(*alarm, check_weekday)) { int64_t time_diff = day_offset * 24 * 60 + alarm_time - current_time; if (day_offset == 0) { time_diff = alarm_time - current_time; } if (time_diff < min_time_diff) { min_time_diff = time_diff; next_alarm = alarm.get(); } break; } } } if (!next_alarm) { return "无活动闹钟"; } // 格式化下一个闹钟信息 std::ostringstream oss; oss << "下个闹钟: " << FormatTime(next_alarm->hour, next_alarm->minute); if (min_time_diff < 24 * 60) { int hours = min_time_diff / 60; int minutes = min_time_diff % 60; if (hours > 0) { oss << " (" << hours << "小时" << minutes << "分钟后)"; } else { oss << " (" << minutes << "分钟后)"; } } else { int days = min_time_diff / (24 * 60); oss << " (" << days << "天后)"; } if (!next_alarm->label.empty()) { oss << " - " << next_alarm->label; } return oss.str(); } bool AlarmManager::SnoozeAlarm(int alarm_id) { if (!initialized_) { return false; } std::lock_guard lock(alarms_mutex_); auto it = std::find_if(alarms_.begin(), alarms_.end(), [alarm_id](const auto& alarm) { return alarm->id == alarm_id; }); if (it != alarms_.end() && (*it)->status == kAlarmTriggered) { if ((*it)->snooze_count < (*it)->max_snooze_count) { (*it)->status = kAlarmSnoozed; (*it)->snooze_count++; (*it)->next_snooze_time = esp_timer_get_time() / 1000000 + (*it)->snooze_minutes * 60; ESP_LOGI(TAG, "Snoozed alarm %d for %d minutes (count: %d/%d)", alarm_id, (*it)->snooze_minutes, (*it)->snooze_count, (*it)->max_snooze_count); if (on_alarm_snoozed_) { on_alarm_snoozed_(**it); } return true; } else { ESP_LOGI(TAG, "Alarm %d exceeded max snooze count, stopping", alarm_id); StopAlarm(alarm_id); } } return false; } bool AlarmManager::StopAlarm(int alarm_id) { if (!initialized_) { return false; } std::lock_guard lock(alarms_mutex_); auto it = std::find_if(alarms_.begin(), alarms_.end(), [alarm_id](const auto& alarm) { return alarm->id == alarm_id; }); if (it != alarms_.end() && ((*it)->status == kAlarmTriggered || (*it)->status == kAlarmSnoozed)) { AlarmStatus old_status = (*it)->status; (*it)->status = ((*it)->repeat_mode == kAlarmOnce) ? kAlarmDisabled : kAlarmEnabled; (*it)->snooze_count = 0; (*it)->next_snooze_time = 0; ESP_LOGI(TAG, "Stopped alarm %d", alarm_id); if (on_alarm_stopped_) { on_alarm_stopped_(**it); } return true; } return false; } void AlarmManager::StopAllActiveAlarms() { if (!initialized_) { return; } std::lock_guard lock(alarms_mutex_); for (auto& alarm : alarms_) { if (alarm->status == kAlarmTriggered || alarm->status == kAlarmSnoozed) { alarm->status = (alarm->repeat_mode == kAlarmOnce) ? kAlarmDisabled : kAlarmEnabled; alarm->snooze_count = 0; alarm->next_snooze_time = 0; if (on_alarm_stopped_) { on_alarm_stopped_(*alarm); } } } ESP_LOGI(TAG, "Stopped all active alarms"); } void AlarmManager::CheckAlarms() { if (!initialized_) { return; } int64_t current_time_seconds = esp_timer_get_time() / 1000000; int64_t current_time_minutes = GetCurrentTimeInMinutes(); std::lock_guard lock(alarms_mutex_); for (auto& alarm : alarms_) { // 检查贪睡闹钟 if (alarm->status == kAlarmSnoozed && current_time_seconds >= alarm->next_snooze_time) { alarm->status = kAlarmTriggered; alarm->next_snooze_time = 0; ESP_LOGI(TAG, "Snooze ended for alarm %d, triggering again", alarm->id); if (on_alarm_triggered_) { on_alarm_triggered_(*alarm); } continue; } // 检查正常闹钟触发 if (alarm->status != kAlarmEnabled) { continue; } int64_t alarm_time_minutes = alarm->hour * 60 + alarm->minute; // 检查是否是触发时间(精确到分钟) if (alarm_time_minutes != current_time_minutes) { continue; } // 检查是否应该在今天触发 if (!ShouldTriggerToday(*alarm)) { continue; } // 防止重复触发(同一分钟内) int64_t current_time_in_seconds = esp_timer_get_time() / 1000000; if (alarm->last_triggered_time > 0 && (current_time_in_seconds - alarm->last_triggered_time) < 60) { continue; } // 触发闹钟 alarm->status = kAlarmTriggered; alarm->last_triggered_time = current_time_in_seconds; alarm->snooze_count = 0; ESP_LOGI(TAG, "Triggering alarm %d: %02d:%02d - %s", alarm->id, alarm->hour, alarm->minute, alarm->label.c_str()); if (on_alarm_triggered_) { on_alarm_triggered_(*alarm); } } } void AlarmManager::SetAlarmTriggeredCallback(AlarmTriggeredCallback callback) { on_alarm_triggered_ = callback; } void AlarmManager::SetAlarmSnoozeCallback(AlarmSnoozeCallback callback) { on_alarm_snoozed_ = callback; } void AlarmManager::SetAlarmStopCallback(AlarmStopCallback callback) { on_alarm_stopped_ = callback; } void AlarmManager::SetDefaultSnoozeMinutes(int minutes) { default_snooze_minutes_ = std::max(1, std::min(60, minutes)); } void AlarmManager::SetDefaultMaxSnoozeCount(int count) { default_max_snooze_count_ = std::max(0, std::min(10, count)); } // 静态工具方法 std::string AlarmManager::FormatTime(int hour, int minute) { std::ostringstream oss; oss << std::setfill('0') << std::setw(2) << hour << ":" << std::setfill('0') << std::setw(2) << minute; return oss.str(); } std::string AlarmManager::FormatAlarmTime(const AlarmItem& alarm) { std::ostringstream oss; oss << FormatTime(alarm.hour, alarm.minute); switch (alarm.repeat_mode) { case kAlarmOnce: oss << " (一次)"; break; case kAlarmDaily: oss << " (每日)"; break; case kAlarmWeekdays: oss << " (工作日)"; break; case kAlarmWeekends: oss << " (周末)"; break; case kAlarmCustom: oss << " (自定义)"; break; } return oss.str(); } bool AlarmManager::IsWeekdayActive(const AlarmItem& alarm, int weekday) { if (alarm.repeat_mode == kAlarmOnce) { return true; // 一次性闹钟在任何一天都可以触发 } return (alarm.weekdays_mask & (1 << weekday)) != 0; } // 私有方法实现 void AlarmManager::LoadAlarmsFromStorage() { std::lock_guard lock(alarms_mutex_); alarms_.clear(); // 读取闹钟数量 int alarm_count = settings_->GetInt("count", 0); ESP_LOGI(TAG, "Loading %d alarms from storage", alarm_count); for (int i = 0; i < alarm_count; i++) { std::string alarm_key = "alarm_" + std::to_string(i); std::string alarm_json = settings_->GetString(alarm_key); if (alarm_json.empty()) { continue; } cJSON* json = cJSON_Parse(alarm_json.c_str()); if (!json) { ESP_LOGW(TAG, "Failed to parse alarm JSON: %s", alarm_key.c_str()); continue; } auto alarm = std::make_unique(); // 解析JSON数据 if (auto id = cJSON_GetObjectItem(json, "id")) alarm->id = id->valueint; if (auto hour = cJSON_GetObjectItem(json, "hour")) alarm->hour = hour->valueint; if (auto minute = cJSON_GetObjectItem(json, "minute")) alarm->minute = minute->valueint; if (auto repeat = cJSON_GetObjectItem(json, "repeat")) alarm->repeat_mode = (AlarmRepeatMode)repeat->valueint; if (auto mask = cJSON_GetObjectItem(json, "weekdays")) alarm->weekdays_mask = mask->valueint; if (auto status = cJSON_GetObjectItem(json, "status")) alarm->status = (AlarmStatus)status->valueint; if (auto label = cJSON_GetObjectItem(json, "label")) alarm->label = label->valuestring; if (auto music = cJSON_GetObjectItem(json, "music")) alarm->music_name = music->valuestring; if (auto snooze_min = cJSON_GetObjectItem(json, "snooze_minutes")) alarm->snooze_minutes = snooze_min->valueint; if (auto max_snooze = cJSON_GetObjectItem(json, "max_snooze")) alarm->max_snooze_count = max_snooze->valueint; // 重置运行时状态 alarm->snooze_count = 0; alarm->last_triggered_time = 0; alarm->next_snooze_time = 0; if (alarm->status == kAlarmTriggered || alarm->status == kAlarmSnoozed) { alarm->status = kAlarmEnabled; } alarms_.push_back(std::move(alarm)); cJSON_Delete(json); } ESP_LOGI(TAG, "Loaded %d alarms successfully", alarms_.size()); } void AlarmManager::SaveAlarmsToStorage() { if (!settings_) { return; } std::lock_guard lock(alarms_mutex_); // 保存闹钟数量 settings_->SetInt("count", alarms_.size()); // 保存每个闹钟 for (size_t i = 0; i < alarms_.size(); i++) { std::string alarm_key = "alarm_" + std::to_string(i); SaveAlarmToStorage(*alarms_[i]); } ESP_LOGI(TAG, "Saved %d alarms to storage", alarms_.size()); } void AlarmManager::SaveAlarmToStorage(const AlarmItem& alarm) { if (!settings_) { return; } cJSON* json = cJSON_CreateObject(); cJSON_AddNumberToObject(json, "id", alarm.id); cJSON_AddNumberToObject(json, "hour", alarm.hour); cJSON_AddNumberToObject(json, "minute", alarm.minute); cJSON_AddNumberToObject(json, "repeat", alarm.repeat_mode); cJSON_AddNumberToObject(json, "weekdays", alarm.weekdays_mask); cJSON_AddNumberToObject(json, "status", alarm.status); cJSON_AddStringToObject(json, "label", alarm.label.c_str()); cJSON_AddStringToObject(json, "music", alarm.music_name.c_str()); cJSON_AddNumberToObject(json, "snooze_minutes", alarm.snooze_minutes); cJSON_AddNumberToObject(json, "max_snooze", alarm.max_snooze_count); char* json_string = cJSON_PrintUnformatted(json); // 找到这个闹钟在数组中的位置 auto it = std::find_if(alarms_.begin(), alarms_.end(), [&alarm](const auto& a) { return a->id == alarm.id; }); if (it != alarms_.end()) { size_t index = std::distance(alarms_.begin(), it); std::string alarm_key = "alarm_" + std::to_string(index); settings_->SetString(alarm_key, json_string); } cJSON_free(json_string); cJSON_Delete(json); } void AlarmManager::RemoveAlarmFromStorage(int alarm_id) { // 重新保存所有闹钟(简单实现) SaveAlarmsToStorage(); } int AlarmManager::GetNextAlarmId() { return next_alarm_id_++; } bool AlarmManager::ShouldTriggerToday(const AlarmItem& alarm) const { if (alarm.repeat_mode == kAlarmOnce) { return true; } int weekday = GetCurrentWeekday(); return IsWeekdayActive(alarm, weekday); } int64_t AlarmManager::GetCurrentTimeInMinutes() const { time_t now; time(&now); struct tm* timeinfo = localtime(&now); return timeinfo->tm_hour * 60 + timeinfo->tm_min; } int AlarmManager::GetCurrentWeekday() const { time_t now; time(&now); struct tm* timeinfo = localtime(&now); return timeinfo->tm_wday; // 0=周日, 1=周一, ..., 6=周六 }