|
|
@@ -8,20 +8,15 @@
|
|
|
#include <Preferences.h>
|
|
|
|
|
|
// =====================================================
|
|
|
-// ESP32-C3 SuperMini + 原玩具公共正极灯板:BLE + MQTT 双模式
|
|
|
+// ESP32-C3 SuperMini + RGB 灯板:BLE + MQTT 双模式
|
|
|
//
|
|
|
// 功能:
|
|
|
-// - 开机始终启动 BLE,支持灯效控制 + WiFi/MQTT 配置
|
|
|
-// - MQTT 模式下同时连接 WiFi/MQTT
|
|
|
-// - 运行长按 BOOT 按钮 3 秒 → 切换 BLE/MQTT 模式并重启
|
|
|
-// - 连续短按 BOOT 按钮 3 下 → 恢复出厂设置并重启
|
|
|
+// - BLE 模式:灯效控制 + 配置
|
|
|
+// - MQTT 模式:灯效控制(接收模式名)
|
|
|
+// - 串口配置:JSON 格式输入
|
|
|
+// - 按钮:短按切换灯效,长按切换 BLE/MQTT
|
|
|
//
|
|
|
-// BLE 配置:
|
|
|
-// Service: b8b7e001-7a6b-4f4f-9a8b-11c0ffee0001
|
|
|
-// Mode: b8b7e002-... (读写/通知 - 灯效模式)
|
|
|
-// Config: b8b7e003-... (读写 - WiFi/MQTT 配置 JSON)
|
|
|
-//
|
|
|
-// 配置 JSON 格式(写入 Config 特征或 MQTT config topic):
|
|
|
+// 配置 JSON 格式(BLE Config 特征或串口输入):
|
|
|
// {
|
|
|
// "wifi_ssid": "xxx",
|
|
|
// "wifi_pass": "xxx",
|
|
|
@@ -30,28 +25,21 @@
|
|
|
// "mqtt_user": "user",
|
|
|
// "mqtt_pass": "pass",
|
|
|
// "mqtt_client": "AI-Beacon-Light",
|
|
|
-// "mqtt_topic": "agent/status",
|
|
|
-// "mqtt_status": "agentLight/status",
|
|
|
-// "mqtt_topic_config": "agent/status/config",
|
|
|
-// "pin_red": 4,
|
|
|
-// "pin_green": 3,
|
|
|
-// "pin_blue": 2
|
|
|
+// "mqtt_topic": "beacon/status",
|
|
|
+// "pin_red": 3,
|
|
|
+// "pin_green": 2,
|
|
|
+// "pin_blue": 4
|
|
|
// }
|
|
|
//
|
|
|
-// 接线方式(默认引脚,可通过配置修改):
|
|
|
-// ESP32 3.3V -> 原灯板 + / 原电池正极
|
|
|
-// ESP32 IO4 -> 220Ω -> 红灯(默认)
|
|
|
-// ESP32 IO3 -> 220Ω -> 绿灯(默认)
|
|
|
-// ESP32 IO2 -> 220Ω -> 蓝灯(默认)
|
|
|
-// ESP32 IO8 -> 状态 LED(固定)
|
|
|
-// ESP32 IO9 -> BOOT 按钮(固定)
|
|
|
+// MQTT 消息格式:
|
|
|
+// 接收:直接发送模式名(如 thinking、error、red)
|
|
|
// =====================================================
|
|
|
|
|
|
// =====================================================
|
|
|
// BLE 配置
|
|
|
// =====================================================
|
|
|
const char* BLE_DEVICE_NAME = "AI-Beacon-Light";
|
|
|
-const char* FW_VERSION = "1.2.0";
|
|
|
+const char* FW_VERSION = "1.3.0";
|
|
|
#define SERVICE_UUID "b8b7e001-7a6b-4f4f-9a8b-11c0ffee0001"
|
|
|
#define MODE_CHAR_UUID "b8b7e002-7a6b-4f4f-9a8b-11c0ffee0001"
|
|
|
#define CONFIG_CHAR_UUID "b8b7e003-7a6b-4f4f-9a8b-11c0ffee0001"
|
|
|
@@ -129,9 +117,7 @@ uint16_t cfgMqttPort = 1883;
|
|
|
String cfgMqttUser = "";
|
|
|
String cfgMqttPass = "";
|
|
|
String cfgMqttClient = "AI-Beacon-Light";
|
|
|
-String cfgMqttTopic = "agent/status";
|
|
|
-String cfgMqttStatus = "agentLight/status";
|
|
|
-String cfgMqttTopicConfig = "agent/status/config";
|
|
|
+String cfgMqttTopic = "beacon/status";
|
|
|
|
|
|
|
|
|
// =====================================================
|
|
|
@@ -146,9 +132,7 @@ void loadConfig() {
|
|
|
cfgMqttUser = preferences.getString("mqtt_user", "");
|
|
|
cfgMqttPass = preferences.getString("mqtt_pass", "");
|
|
|
cfgMqttClient = preferences.getString("mqtt_client", "AI-Beacon-Light");
|
|
|
- cfgMqttTopic = preferences.getString("mqtt_topic", "agent/status");
|
|
|
- cfgMqttStatus = preferences.getString("mqtt_status", "agentLight/status");
|
|
|
- cfgMqttTopicConfig = preferences.getString("mqtt_topic_cfg", "agent/status/config");
|
|
|
+ cfgMqttTopic = preferences.getString("mqtt_topic", "beacon/status");
|
|
|
redPin = preferences.getUInt("pin_red", 3);
|
|
|
greenPin = preferences.getUInt("pin_green", 2);
|
|
|
bluePin = preferences.getUInt("pin_blue", 4);
|
|
|
@@ -167,8 +151,6 @@ String getConfigJson() {
|
|
|
doc["mqtt_user"] = cfgMqttUser;
|
|
|
doc["mqtt_client"] = cfgMqttClient;
|
|
|
doc["mqtt_topic"] = cfgMqttTopic;
|
|
|
- doc["mqtt_status"] = cfgMqttStatus;
|
|
|
- doc["mqtt_topic_config"] = cfgMqttTopicConfig;
|
|
|
doc["comm_mode"] = useMQTT ? 1 : 0;
|
|
|
doc["pin_red"] = redPin;
|
|
|
doc["pin_green"] = greenPin;
|
|
|
@@ -203,10 +185,6 @@ void saveConfigFromJson(const String& json) {
|
|
|
preferences.putString("mqtt_client", doc["mqtt_client"].as<String>());
|
|
|
if (doc.containsKey("mqtt_topic"))
|
|
|
preferences.putString("mqtt_topic", doc["mqtt_topic"].as<String>());
|
|
|
- if (doc.containsKey("mqtt_status"))
|
|
|
- preferences.putString("mqtt_status", doc["mqtt_status"].as<String>());
|
|
|
- if (doc.containsKey("mqtt_topic_config"))
|
|
|
- preferences.putString("mqtt_topic_cfg", doc["mqtt_topic_config"].as<String>());
|
|
|
if (doc.containsKey("pin_red"))
|
|
|
preferences.putUInt("pin_red", doc["pin_red"].as<uint8_t>());
|
|
|
if (doc.containsKey("pin_green"))
|
|
|
@@ -288,12 +266,6 @@ bool isValidMode(String mode) {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
-void publishStatus() {
|
|
|
- if (useMQTT && mqttClient.connected()) {
|
|
|
- mqttClient.publish(cfgMqttStatus.c_str(), currentMode.c_str(), true);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
void notifyMode() {
|
|
|
if (pModeCharacteristic) {
|
|
|
pModeCharacteristic->setValue(currentMode.c_str());
|
|
|
@@ -325,9 +297,8 @@ void setMode(String mode) {
|
|
|
else if (mode == "cyan") fadeToStatic(0, GREEN_MAX, BLUE_MAX, 80);
|
|
|
else if (mode == "magenta") fadeToStatic(RED_MAX, 0, BLUE_MAX, 80);
|
|
|
else if (mode == "white") fadeToStatic(RED_MAX, GREEN_MAX, BLUE_MAX, 80);
|
|
|
- else if (mode == "off") allOff();
|
|
|
+ if (mode == "off") allOff();
|
|
|
|
|
|
- publishStatus();
|
|
|
notifyMode();
|
|
|
}
|
|
|
|
|
|
@@ -579,32 +550,13 @@ void setupBLE() {
|
|
|
void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
|
|
String message = "";
|
|
|
for (unsigned int i = 0; i < length; i++) message += (char)payload[i];
|
|
|
+ message.trim();
|
|
|
Serial.print("MQTT: "); Serial.print(topic); Serial.print(" -> "); Serial.println(message);
|
|
|
-
|
|
|
- if (String(topic) == cfgMqttTopicConfig) {
|
|
|
- saveConfigFromJson(message);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- JsonDocument doc;
|
|
|
- if (deserializeJson(doc, message)) { setMode(message); return; }
|
|
|
- const char* code = doc["code"];
|
|
|
- if (code) {
|
|
|
- String c = String(code);
|
|
|
- if (c == "idle") setMode("off");
|
|
|
- else if (c == "busy" || c == "running") setMode("busy");
|
|
|
- else if (c == "retry" || c == "permission") setMode("alarm");
|
|
|
- else if (c == "pending") setMode("yellow");
|
|
|
- else if (c == "reasoning") setMode("thinking");
|
|
|
- else if (c == "using_tool") setMode("ai");
|
|
|
- else if (c == "error") setMode("error");
|
|
|
- else setMode(c);
|
|
|
- }
|
|
|
+ if (isValidMode(message)) setMode(message);
|
|
|
}
|
|
|
|
|
|
void mqttSubscribe() {
|
|
|
mqttClient.subscribe(cfgMqttTopic.c_str());
|
|
|
- mqttClient.subscribe(cfgMqttTopicConfig.c_str());
|
|
|
}
|
|
|
|
|
|
void updateConnection() {
|
|
|
@@ -688,7 +640,6 @@ void handleMqttReconnect() {
|
|
|
if (mqttClient.connect(cfgMqttClient.c_str(), cfgMqttUser.c_str(), cfgMqttPass.c_str())) {
|
|
|
Serial.println("MQTT reconnected.");
|
|
|
mqttSubscribe();
|
|
|
- publishStatus();
|
|
|
}
|
|
|
}
|
|
|
|