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);