|
|
@@ -6,8 +6,6 @@
|
|
|
#include <BLEUtils.h>
|
|
|
#include <BLE2902.h>
|
|
|
#include <Preferences.h>
|
|
|
-#include <HTTPClient.h>
|
|
|
-#include <Update.h>
|
|
|
|
|
|
// =====================================================
|
|
|
// ESP32-C3 SuperMini + 原玩具公共正极灯板:BLE + MQTT 双模式
|
|
|
@@ -36,8 +34,7 @@
|
|
|
// "mqtt_topic_config": "agent/status/config",
|
|
|
// "pin_red": 4,
|
|
|
// "pin_green": 3,
|
|
|
-// "pin_yellow": 2,
|
|
|
-// "ota_url": "https://example.com/firmware.bin"
|
|
|
+// "pin_yellow": 2
|
|
|
// }
|
|
|
//
|
|
|
// 接线方式(默认引脚,可通过配置修改):
|
|
|
@@ -106,8 +103,6 @@ String cfgMqttClient = "AI-Light";
|
|
|
String cfgMqttTopic = "agent/status";
|
|
|
String cfgMqttStatus = "agentLight/status";
|
|
|
String cfgMqttTopicConfig = "agent/status/config";
|
|
|
-String cfgOtaUrl = "";
|
|
|
-bool otaInProgress = false;
|
|
|
|
|
|
|
|
|
// =====================================================
|
|
|
@@ -128,7 +123,6 @@ void loadConfig() {
|
|
|
redPin = preferences.getUInt("pin_red", 4);
|
|
|
greenPin = preferences.getUInt("pin_green", 3);
|
|
|
yellowPin = preferences.getUInt("pin_yellow", 2);
|
|
|
- cfgOtaUrl = preferences.getString("ota_url", "");
|
|
|
}
|
|
|
|
|
|
bool isConfigComplete() {
|
|
|
@@ -150,7 +144,6 @@ String getConfigJson() {
|
|
|
doc["pin_red"] = redPin;
|
|
|
doc["pin_green"] = greenPin;
|
|
|
doc["pin_yellow"] = yellowPin;
|
|
|
- doc["ota_url"] = cfgOtaUrl;
|
|
|
String out;
|
|
|
serializeJson(doc, out);
|
|
|
return out;
|
|
|
@@ -191,8 +184,6 @@ void saveConfigFromJson(const String& json) {
|
|
|
preferences.putUInt("pin_green", doc["pin_green"].as<uint8_t>());
|
|
|
if (doc.containsKey("pin_yellow"))
|
|
|
preferences.putUInt("pin_yellow", doc["pin_yellow"].as<uint8_t>());
|
|
|
- if (doc.containsKey("ota_url"))
|
|
|
- preferences.putString("ota_url", doc["ota_url"].as<String>());
|
|
|
|
|
|
Serial.println("Config saved. Restarting...");
|
|
|
delay(500);
|
|
|
@@ -507,10 +498,6 @@ class ServerCallbacks : public BLEServerCallbacks {
|
|
|
class ModeCharCallbacks : public BLECharacteristicCallbacks {
|
|
|
void onWrite(BLECharacteristic* c) {
|
|
|
String val = c->getValue();
|
|
|
- if (val == "ota") {
|
|
|
- performOTA();
|
|
|
- return;
|
|
|
- }
|
|
|
setMode(val);
|
|
|
}
|
|
|
void onRead(BLECharacteristic* c) { c->setValue(currentMode.c_str()); }
|
|
|
@@ -575,10 +562,6 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
|
|
else if (c == "reasoning") setMode("thinking");
|
|
|
else if (c == "using_tool") setMode("ai");
|
|
|
else if (c == "error") setMode("error");
|
|
|
- else if (c == "ota") {
|
|
|
- performOTA();
|
|
|
- return;
|
|
|
- }
|
|
|
else setMode(c);
|
|
|
}
|
|
|
}
|
|
|
@@ -632,114 +615,6 @@ void checkMQTTConnection() {
|
|
|
}
|
|
|
|
|
|
|
|
|
-// =====================================================
|
|
|
-// OTA 固件更新
|
|
|
-// =====================================================
|
|
|
-
|
|
|
-void notifyOtaStatus(const String& status) {
|
|
|
- if (pModeCharacteristic && bleDeviceConnected) {
|
|
|
- pModeCharacteristic->setValue(status.c_str());
|
|
|
- pModeCharacteristic->notify();
|
|
|
- }
|
|
|
- if (useMQTT && mqttClient.connected()) {
|
|
|
- mqttClient.publish(cfgMqttStatus.c_str(), status.c_str(), true);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void performOTA() {
|
|
|
- Serial.println("=== OTA Start ===");
|
|
|
-
|
|
|
- if (otaInProgress) {
|
|
|
- Serial.println("OTA already in progress");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (cfgOtaUrl.length() == 0) {
|
|
|
- Serial.println("OTA URL not configured");
|
|
|
- notifyOtaStatus("ota:no_url");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (WiFi.status() != WL_CONNECTED) {
|
|
|
- Serial.println("WiFi not connected");
|
|
|
- notifyOtaStatus("ota:no_wifi");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- otaInProgress = true;
|
|
|
- notifyOtaStatus("ota:downloading");
|
|
|
-
|
|
|
- HTTPClient http;
|
|
|
- http.begin(cfgOtaUrl);
|
|
|
- http.setTimeout(30000);
|
|
|
-
|
|
|
- int httpCode = http.GET();
|
|
|
- Serial.printf("HTTP GET: %d\n", httpCode);
|
|
|
-
|
|
|
- if (httpCode != 200) {
|
|
|
- Serial.printf("HTTP error: %d\n", httpCode);
|
|
|
- notifyOtaStatus("ota:error");
|
|
|
- http.end();
|
|
|
- otaInProgress = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- int contentLength = http.getSize();
|
|
|
- Serial.printf("Firmware size: %d bytes\n", contentLength);
|
|
|
-
|
|
|
- if (contentLength <= 0) {
|
|
|
- Serial.println("Invalid content length");
|
|
|
- notifyOtaStatus("ota:error");
|
|
|
- http.end();
|
|
|
- otaInProgress = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!Update.begin(contentLength)) {
|
|
|
- Serial.println("Update.begin failed");
|
|
|
- notifyOtaStatus("ota:error");
|
|
|
- http.end();
|
|
|
- otaInProgress = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- WiFiClient* stream = http.getStreamPtr();
|
|
|
- uint8_t buf[1024];
|
|
|
- int written = 0;
|
|
|
- unsigned long lastProgress = millis();
|
|
|
-
|
|
|
- while (http.connected() && written < contentLength) {
|
|
|
- size_t size = stream->available();
|
|
|
- if (size) {
|
|
|
- int bytesRead = stream->readBytes(buf, min(size, sizeof(buf)));
|
|
|
- size_t bytesWritten = Update.write(buf, bytesRead);
|
|
|
- written += bytesWritten;
|
|
|
-
|
|
|
- if (millis() - lastProgress >= 1000) {
|
|
|
- Serial.printf("Progress: %d/%d (%.1f%%)\n", written, contentLength, (float)written / contentLength * 100);
|
|
|
- lastProgress = millis();
|
|
|
- }
|
|
|
- }
|
|
|
- delay(1);
|
|
|
- }
|
|
|
-
|
|
|
- Serial.printf("Written: %d/%d\n", written, contentLength);
|
|
|
-
|
|
|
- if (Update.end(true)) {
|
|
|
- Serial.println("OTA success!");
|
|
|
- notifyOtaStatus("ota:success");
|
|
|
- delay(1000);
|
|
|
- ESP.restart();
|
|
|
- } else {
|
|
|
- Serial.printf("OTA error: %s\n", Update.errorString());
|
|
|
- notifyOtaStatus("ota:error");
|
|
|
- }
|
|
|
-
|
|
|
- http.end();
|
|
|
- otaInProgress = false;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
// =====================================================
|
|
|
// 初始化
|
|
|
// =====================================================
|