3 Commits
Author SHA1 Message Date
clear 665e230192 Release RC2.0 2026-05-08 14:04:41 +08:00
clear 5288ffa07d Remove release artifacts from repo 2026-05-08 14:00:31 +08:00
clear 97c43d282c Release RC1.0.5 2026-05-08 13:52:26 +08:00
4 changed files with 79 additions and 21 deletions

No files matched your search

+2
View File
@@ -3,3 +3,5 @@
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
*.bin
release_v*.json
Binary file not shown.
+9 -12
View File
@@ -1,10 +1,10 @@
# ClearESP WindSensors
# ClearMCU-Wind
## 项目简介
ClearESP WindSensors 是基于 `ESP32-C3` 的 RS485 风速风向传感器采集网关固件,面向现场部署、批量站号配置、Web 运维和 MQTT 上报场景。
ClearMCU-Wind 是基于 `ESP32-C3` 的 RS485 风速风向传感器采集网关固件,面向现场部署、批量站号配置、Web 运维和 MQTT 上报场景。
当前固件版本:`RC1.0.4`
当前固件版本:`RC2.0`
## 主要功能
@@ -101,7 +101,7 @@ ClearESP WindSensors 是基于 `ESP32-C3` 的 RS485 风速风向传感器采集
AP 名称格式:
- `ClearESP-Wind-<MAC>`
- `ClearMCU-Wind-<MAC>`
### 4. Web 页面
@@ -209,7 +209,7 @@ AP 名称格式:
```json
{
"mac": "B43A455471D4",
"firmware_version": "RC1.0.4",
"firmware_version": "RC2.0",
"uptime_ms": 123456,
"sensors": [
{
@@ -241,11 +241,8 @@ platformio run
platformio run -t upload
```
## RC1.0.4 变更
## RC2.0 变更
- MQTT 仅保留 `/realtime` 上报与页面展示
- 系统状态页显示固件版本
- 云服务页 OTA 卡片改为现场可用的检查更新 / 下载升级流程
- OTA 页面不再向用户展示项目地址或固件直链
- 补齐 OTA 检查与升级接口
- 修正文档中文乱码并同步更新说明
- 品牌字样统一更新为 `ClearMCU-Wind`
- 固件版本升级为 `RC2.0`
- 保留既有 OTA、MQTT、Web 管理与现场配置能力
+68 -9
View File
@@ -30,8 +30,10 @@ constexpr uint32_t MODBUS_RESPONSE_TIMEOUT_MS = 500;
constexpr uint32_t WIFI_RETRY_INTERVAL_MS = 15000;
constexpr uint32_t WIFI_CONNECT_TIMEOUT_MS = 20000;
constexpr bool ENABLE_BOOT_DIAGNOSTICS = false;
constexpr char FIRMWARE_VERSION[] = "RC1.0.4";
constexpr char FIRMWARE_VERSION[] = "RC2.0";
constexpr char OTA_PROJECT_URL[] = "http://107.173.157.41:3000/clear/wind_vt_esp32";
constexpr char OTA_LATEST_RELEASE_API_URL[] =
"http://107.173.157.41:3000/api/v1/repos/clear/wind_vt_esp32/releases/latest";
constexpr uint16_t MQTT_DEFAULT_PORT = 1883;
constexpr uint32_t MQTT_RETRY_INTERVAL_MS = 10000;
constexpr uint32_t MQTT_PUBLISH_INTERVAL_MS = 1000;
@@ -108,7 +110,7 @@ const char WEB_PAGE[] PROGMEM = R"HTML(
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>ClearESP Wind</title>
<title>ClearMCU-Wind</title>
<style>
:root {
--bg0: #081118;
@@ -478,7 +480,7 @@ const char WEB_PAGE[] PROGMEM = R"HTML(
<section class="topbar">
<div class="brandline">
<div class="brand">
<h1>ClearESP WindSensors</h1>
<h1>ClearMCU-Wind</h1>
<div class="brand-note">数字植物实验室</div>
</div>
</div>
@@ -598,6 +600,16 @@ const char WEB_PAGE[] PROGMEM = R"HTML(
<section id="page-cloud" class="panel page">
<h2>&#20113;&#26381;&#21153;</h2>
<div class="stack">
<div class="api-card">
<div class="label">OTA</div>
<div class="subtext" id="otaIntro">OTA 需要设备先连接外部 WiFi。检测到新版本后,可直接下载并升级。</div>
<div class="subtext" id="otaSummary">当前固件版本 -- | 最新版本 --</div>
<div class="subtext" id="otaStatusText" style="color:#cfe7de;">--</div>
<div class="actions">
<button id="btnOtaCheck" class="action ghost" onclick="checkOtaUpdate()">检查更新</button>
<button id="btnOtaUpdate" class="action" onclick="startOtaUpdate()">下载并升级</button>
</div>
</div>
<div class="subtext">
&#37197;&#32622; MQTT &#26381;&#21153;&#22120;&#21518;&#65292;&#35774;&#22791;&#20250;&#33258;&#21160;&#36830;&#25509;&#24182;&#19978;&#25253;&#20256;&#24863;&#22120;&#21015;&#34920;&#19982;&#23454;&#26102;&#25968;&#25454;&#12290;&#19978;&#25253;&#20869;&#23481;&#20250;&#24102;&#19978;&#35774;&#22791; MAC&#65292;&#29992;&#20110;&#21306;&#20998;&#35774;&#22791;&#36523;&#20221;&#12290;
</div>
@@ -990,10 +1002,57 @@ const char WEB_PAGE[] PROGMEM = R"HTML(
}
}
function cleanupDuplicateOtaNodes() {
const duplicatedIds = ['otaSummary', 'otaStatusText', 'btnOtaCheck', 'btnOtaUpdate'];
duplicatedIds.forEach((id) => {
const nodes = document.querySelectorAll(`[id="${id}"]`);
nodes.forEach((node, index) => {
if (index > 0) {
const card = node.closest('.api-card');
if (card) {
card.remove();
} else {
node.remove();
}
}
});
});
}
function renderOtaPanel(data) {
const intro = document.getElementById('otaIntro');
const summary = document.getElementById('otaSummary');
const status = document.getElementById('otaStatusText');
const btnCheck = document.getElementById('btnOtaCheck');
const btnUpdate = document.getElementById('btnOtaUpdate');
const latestVersion = data.otaLatestVersion
? (data.otaLatestVersion.startsWith('v') ? `RC${data.otaLatestVersion.slice(1)}` : data.otaLatestVersion)
: '--';
if (intro) {
intro.textContent = 'OTA 需要设备先连接外部 WiFi。检测到新版本后,可直接下载并升级。';
}
if (summary) {
summary.textContent = `当前固件版本 ${data.firmwareVersion} | 最新版本 ${latestVersion}`;
}
if (status) {
status.textContent = data.otaStatus || '--';
}
if (btnCheck) {
btnCheck.disabled = busy;
btnCheck.textContent = '检查更新';
}
if (btnUpdate) {
btnUpdate.disabled = busy || !data.otaUpdateAvailable;
btnUpdate.textContent = '下载并升级';
}
}
document.addEventListener('visibilitychange', () => {
scheduleRefresh(document.hidden ? 1200 : 100);
});
document.addEventListener('DOMContentLoaded', () => {
cleanupDuplicateOtaNodes();
const ssidInput = document.getElementById('wifiSsid');
const passInput = document.getElementById('wifiPass');
[ssidInput, passInput].forEach((input) => {
@@ -1112,7 +1171,7 @@ String otaReleaseTag() {
}
String otaAssetName() {
return "ClearESP-WindSensors-ESP32C3-" + otaReleaseTag() + ".bin";
return "ClearMCU-Wind-ESP32C3-" + otaReleaseTag() + ".bin";
}
String otaReleaseUrl() {
@@ -1124,7 +1183,7 @@ String otaBinUrl() {
}
String otaAssetNameForTag(const String &tag) {
return "ClearESP-WindSensors-ESP32C3-" + tag + ".bin";
return "ClearMCU-Wind-ESP32C3-" + tag + ".bin";
}
String otaReleaseUrlForTag(const String &tag) {
@@ -1610,7 +1669,7 @@ bool fetchLatestOtaRelease(String &latestTag, String &latestBin, String &error)
HTTPClient http;
WiFiClient client;
const String url = String(OTA_PROJECT_URL) + "/api/v1/repos/clear/wind_vt_esp32/releases/latest";
const String url = OTA_LATEST_RELEASE_API_URL;
if (!http.begin(client, url)) {
error = "无法建立 OTA 检查连接";
return false;
@@ -1740,7 +1799,7 @@ bool startMqttConnect(bool forceNow) {
mqttClient->setServer(state.mqttHost.c_str(), state.mqttPort);
mqttClient->setBufferSize(MQTT_BUFFER_SIZE);
const String clientId = "ClearESP-" + hexMacString();
const String clientId = "ClearMCU-" + hexMacString();
const bool ok = state.mqttUsername.isEmpty()
? mqttClient->connect(clientId.c_str())
: mqttClient->connect(clientId.c_str(), state.mqttUsername.c_str(),
@@ -2111,7 +2170,7 @@ String buildNetworkJson() {
String buildSystemJson() {
String json = "{";
json += "\"device\":\"ClearESP-Wind\",";
json += "\"device\":\"ClearMCU-Wind\",";
json += "\"mac\":\"" + hexMacString() + "\",";
json += "\"firmware_version\":\"" + String(FIRMWARE_VERSION) + "\",";
json += "\"ota_latest_version\":\"" + jsonEscaped(state.otaLatestVersion) + "\",";
@@ -2429,7 +2488,7 @@ void setupWebServer() {
}
void setupWiFiAp() {
state.apSsid = "ClearESP-Wind-" + hexMacString();
state.apSsid = "ClearMCU-Wind-" + hexMacString();
WiFi.mode(WIFI_AP_STA);
WiFi.setAutoReconnect(true);
WiFi.persistent(false);