diff --git a/src/config.h b/src/config.h index d031bb6..43b298a 100644 --- a/src/config.h +++ b/src/config.h @@ -1,6 +1,12 @@ #ifndef CONFIG_H #define CONFIG_H +// 固件版本信息 +#define FIRMWARE_VERSION "v2.1.0" +#define BUILD_DATE __DATE__ +#define BUILD_TIME __TIME__ +#define FIRMWARE_NAME "PetIO" + // WiFi 配置 #define DEFAULT_AP_SSID "PetIO_Setup" #define WIFI_TIMEOUT 30000 // 30秒 diff --git a/src/main.cpp b/src/main.cpp index bb98263..f4fcfe7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,7 +17,7 @@ WebServer webServer(&wifiManager, &timerManager, &timeManager); unsigned long lastUpdate = 0; unsigned long lastWiFiCheck = 0; unsigned long lastTimeUpdate = 0; -const unsigned long UPDATE_INTERVAL = 1000; // 1秒 +const unsigned long UPDATE_INTERVAL = 10; // 10毫秒 - 高精度定时器更新 const unsigned long WIFI_CHECK_INTERVAL = 30000; // 30秒 const unsigned long TIME_UPDATE_INTERVAL = 10000; // 10秒 @@ -100,9 +100,16 @@ void loop() { unsigned long currentTime = millis(); - // 处理 Web 请求 + // 处理 Web 请求 (优先级最高) webServer.handleClient(); + // 高频更新定时器 (10ms间隔,确保定时器精度) + if (currentTime - lastUpdate >= UPDATE_INTERVAL) + { + timerManager.update(); + lastUpdate = currentTime; + } + // 定期更新时间同步 if (currentTime - lastTimeUpdate >= TIME_UPDATE_INTERVAL) { @@ -110,13 +117,6 @@ void loop() lastTimeUpdate = currentTime; } - // 定期更新定时器 - if (currentTime - lastUpdate >= UPDATE_INTERVAL) - { - timerManager.update(); - lastUpdate = currentTime; - } - // 定期检查 WiFi 连接 if (currentTime - lastWiFiCheck >= WIFI_CHECK_INTERVAL) { diff --git a/src/timer_manager.cpp b/src/timer_manager.cpp index a162263..a8b561b 100644 --- a/src/timer_manager.cpp +++ b/src/timer_manager.cpp @@ -81,7 +81,8 @@ void TimerManager::update() { String modeStr = timers[i].isPWM ? " PWM(" + String(timers[i].pwmValue) + ")" : ""; Serial.println("定时器 " + String(i) + " 激活,引脚 " + String(timers[i].pin) + " 开启" + modeStr + - (timers[i].repeatDaily ? " (每天重复)" : " (单次)")); + (timers[i].repeatDaily ? " (每天重复)" : " (单次)") + + ", 预期运行时间: " + String(timers[i].duration * 1000.0) + "ms"); stateChanged = true; @@ -94,13 +95,13 @@ void TimerManager::update() { // 检查是否需要关闭 if (timers[i].isActive && - currentTime - timers[i].startTime >= (unsigned long)(timers[i].duration * 1000.0)) { + currentTime - timers[i].startTime >= (unsigned long)(timers[i].duration * 1000.0 + 0.5)) { timers[i].isActive = false; timers[i].realStartTime = 0; // 清理真实时间戳 setPin(timers[i].pin, LOW, 0); - Serial.println("定时器 " + String(i) + " 完成,引脚 " + String(timers[i].pin) + " 关闭"); + Serial.println("定时器 " + String(i) + " 完成,引脚 " + String(timers[i].pin) + " 关闭,实际运行时间: " + String(currentTime - timers[i].startTime) + "ms"); stateChanged = true; } } diff --git a/src/web_pages.h b/src/web_pages.h index 9ac2044..c88a561 100644 --- a/src/web_pages.h +++ b/src/web_pages.h @@ -640,6 +640,8 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral( systemInfo: null }; + let isLoadingData = false; + // --- Class definitions for styling --- const activeTabClasses = ['active', 'text-indigo-600', 'font-semibold']; const inactiveTabClasses = ['text-gray-500', 'hover:text-gray-700']; @@ -653,10 +655,34 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral( tab.classList.add(...inactiveTabClasses); } }); + + // Set current time as default for timer + setCurrentTimeAsDefault(); + loadData(); - setInterval(loadData, 5000); + // 使用异步轮询替代 setInterval + startPolling(); }); + function setCurrentTimeAsDefault() { + const now = new Date(); + const hours = String(now.getHours()).padStart(2, '0'); + const minutes = String(now.getMinutes()).padStart(2, '0'); + const currentTime = `${hours}:${minutes}`; + document.getElementById('timer-time').value = currentTime; + } + + function startPolling() { + async function poll() { + if (!isLoadingData) { + await loadData(); + } + // 等待5秒后再次轮询 + setTimeout(poll, 5000); + } + poll(); + } + function switchTab(tabName, clickedTab) { document.querySelectorAll('.tab-content').forEach(content => content.classList.add('hidden')); document.querySelectorAll('.tab').forEach(tab => { @@ -674,6 +700,11 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral( } async function loadData() { + if (isLoadingData) { + return; // 如果正在加载,直接返回 + } + + isLoadingData = true; try { const [statusRes, timersRes, pinsRes] = await Promise.all([ fetch('/api/status'), @@ -698,6 +729,8 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral( } catch (error) { console.error('加载数据失败:', error); document.getElementById('connection-status').innerHTML = `加载失败`; + } finally { + isLoadingData = false; } } @@ -1128,8 +1161,8 @@ const char INDEX_HTML[] PROGMEM = R"rawliteral( const response = await fetch('/api/system'); if (response.ok) { const data = await response.json(); - document.getElementById('current-version').textContent = `v1.0.0`; - document.getElementById('build-time').textContent = new Date().toLocaleDateString(); + document.getElementById('current-version').textContent = data.firmwareVersion || 'v1.0.0'; + document.getElementById('build-time').textContent = data.buildDateTime || '未知'; document.getElementById('firmware-chip-id').textContent = data.chipId || '未知'; } } catch (error) { diff --git a/src/web_server.cpp b/src/web_server.cpp index 0eed2d0..69f894a 100644 --- a/src/web_server.cpp +++ b/src/web_server.cpp @@ -1,4 +1,5 @@ #include "web_server.h" +#include "config.h" #include #include @@ -134,6 +135,13 @@ void WebServer::handleGetSystemInfo() { JsonDocument doc; + // 固件信息 + doc["firmwareVersion"] = FIRMWARE_VERSION; + doc["firmwareName"] = FIRMWARE_NAME; + doc["buildDate"] = BUILD_DATE; + doc["buildTime"] = BUILD_TIME; + doc["buildDateTime"] = String(BUILD_DATE) + " " + String(BUILD_TIME); + // 基本系统信息 doc["chipId"] = String(ESP.getChipId(), HEX); doc["flashChipId"] = String(ESP.getFlashChipId(), HEX);