#include <Arduino.h>

// 定义引脚数组 分别代表水位 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
const int pins[] = { 25, 26, 15, 2, 0, 4, 16, 17, 21, 22 };
const int numPins = sizeof(pins) / sizeof(pins[0]);

// MQTT配置参数
const char* mqttBroker = "wulian.nobiggie.cn";
const int mqttPort = 1883;
const char* mqttClientId = "A7670C";
const char* mqttUsername = "aaaaaaa";
const char* mqttPassword = "abcdefg";
const char* pubTopic = "wulian/water";
const char* subTopic = "wulian/admin";

// 状态变量
bool mqttConnected = false;
unsigned long lastReconnectAttempt = 0;
unsigned long lastPublishTime = 0;
unsigned long lastWaterCheckTime = 0;
const unsigned long publishInterval = 5000;     // 发布间隔(毫秒)
const unsigned long waterCheckInterval = 1000;  // 水位检测间隔(毫秒)

// 水位相关变量
int currentWaterLevel = 0;
int lastPublishedLevel = -1;          // 初始化为-1表示尚未发布过
const int levelChangeThreshold = 10;  // 水位变化超过此值才发布更新

// 串口通信缓冲区和状态
#define MAX_RESPONSE_LENGTH 256
char responseBuffer[MAX_RESPONSE_LENGTH];
int responseIndex = 0;
bool awaitingResponse = false;
String currentCommand = "";

void setup() {
  Serial.begin(115200);

  Serial.println("水位监测系统初始化中...");

  // 设置水位检测引脚为输入模式
  for (int i = 0; i < numPins; i++) {
    pinMode(pins[i], INPUT);
  }

  // 初始化模块
  if (initModule()) {
    Serial.println("模块初始化成功");
    // 连接MQTT服务器
    reconnect();
  } else {
    Serial.println("模块初始化失败");
  }
}

void loop() {
  // 处理串口响应
  handleSerialResponses();

  // 定期检测水位
  if (millis() - lastWaterCheckTime > waterCheckInterval) {
    lastWaterCheckTime = millis();
    checkWaterLevel();
  }

  // 保持MQTT连接
  if (!mqttConnected) {
    unsigned long now = millis();
    // 每5秒尝试重连
    if (now - lastReconnectAttempt > 5000) {
      lastReconnectAttempt = now;
      reconnect();
    }
  } else {
    // 当水位变化超过阈值时发布更新
    if (shouldPublishUpdate()) {
      publishWaterLevel();
      lastPublishedLevel = currentWaterLevel;
      Serial.print("已发布更新水位: ");
      Serial.print(currentWaterLevel);
      Serial.println("%");
    }
  }
}

// 检测当前水位
void checkWaterLevel() {
  int newLevel = 0;

  // 遍历所有引脚，找到最高水位
  for (int i = 0; i < numPins; i++) {
    if (digitalRead(pins[i]) == LOW) {
      newLevel = (i + 1) * 10;  // 转换为百分比
    }
  }

  // 如果水位发生变化，打印日志
  if (newLevel != currentWaterLevel) {
    Serial.print("水位更新: ");
    Serial.print(currentWaterLevel);
    Serial.print("% -> ");
    Serial.print(newLevel);
    Serial.println("%");
    currentWaterLevel = newLevel;
  }
}

// 判断是否应该发布水位更新
bool shouldPublishUpdate() {
  // 如果还没有发布过任何水位信息，立即发布
  if (lastPublishedLevel == -1) {
    return true;
  }

  // 计算当前水位与上次发布水位的差值
  int levelDifference = abs(currentWaterLevel - lastPublishedLevel);

  // 当差值达到或超过阈值时发布更新
  return (levelDifference >= levelChangeThreshold);
}

// 初始化模块
bool initModule() {
  // 重置模块
  resetModule();

  // 检查模块响应
  if (!sendATCommand("AT", "OK", 2000)) return false;

  // 关闭回显
  if (!sendATCommand("ATE0", "OK", 2000)) return false;

  // 检查SIM卡状态
  if (!sendATCommand("AT+CPIN?", "READY", 5000)) return false;

  // 等待网络注册
  if (!waitForNetworkRegistration()) return false;

  // 配置MQTT主题参数模式
  if (!sendATCommand("AT+CMQTTCFG=\"argtopic\",0,1,1", "OK", 5000)) return false;

  return true;
}

// 重置模块
void resetModule() {
  pinMode(9, OUTPUT);  // 假设复位引脚为D9
  digitalWrite(9, LOW);
  delay(200);
  digitalWrite(9, HIGH);
  delay(3000);  // 等待模块启动
}

// 等待网络注册
bool waitForNetworkRegistration() {
  Serial.println("等待网络注册...");
  unsigned long startTime = millis();

  while (millis() - startTime < 30000) {  // 超时30秒
    if (sendATCommand("AT+CREG?", "+CREG: 0,1", 2000) || sendATCommand("AT+CREG?", "+CREG: 0,5", 2000)) {
      Serial.println("网络注册成功");
      return true;
    }
    delay(1000);
  }

  //Serial.println("网络注册超时");
  return false;
}

// 连接MQTT服务器和订阅主题
bool reconnect() {
  Serial.println("尝试连接MQTT服务器...");

  // 启动MQTT
  if (!sendATCommand("AT+CMQTTSTART", "OK", 5000)) return false;

  // 设置客户端ID
  String cmd = "AT+CMQTTACCQ=0,\"";
  cmd += mqttClientId;
  cmd += "\"";
  if (!sendATCommand(cmd.c_str(), "OK", 5000)) return false;

  // 连接到MQTT代理
  cmd = "AT+CMQTTCONNECT=0,\"tcp://";
  cmd += mqttBroker;
  cmd += ":";
  cmd += String(mqttPort);
  cmd += "\",120,1,\"";
  cmd += mqttUsername;
  cmd += "\",\"";
  cmd += mqttPassword;
  cmd += "\"";
  if (!sendATCommand(cmd.c_str(), "OK", 15000)) return false;

  // 订阅主题 - 按照AT指令序列实现
  cmd = "AT+CMQTTSUB=0,";
  cmd += String(strlen(subTopic));
  cmd += ",0";
  if (!sendATCommand(cmd.c_str(), "OK", 5000)) return false;
  if (!sendATCommand(subTopic, "OK", 5000)) return false;
  delay(200);
  Serial.println(subTopic);

  mqttConnected = true;
  //Serial.println("MQTT连接成功");
  return true;
}

// 发布水位信息
bool publishWaterLevel() {
  if (!mqttConnected) return false;

  Serial.print("发布水位信息: ");
  // 构建消息内容
  String message = String(currentWaterLevel);

  // 按照AT指令序列实现发布流程
  // 设置发布主题
  String cmd = "AT+CMQTTTOPIC=0,";
  cmd += String(strlen(pubTopic));
  delay(200);
  Serial.println(pubTopic);

  // 设置发布负载
  cmd = "AT+CMQTTPAYLOAD=0,";
  cmd += String(message.length());
  //if (!sendATCommand(cmd.c_str(), "OK", 5000)) return false;
  if (!sendATCommand(message.c_str(), "OK", 5000)) return false;

  // 发布消息
  cmd = "AT+CMQTTPUB=0,1,";
  cmd += String(message.length());
  return sendATCommand(cmd.c_str(), "OK", 5000);
}

// 处理串口响应
void handleSerialResponses() {
  static unsigned long lastCharTime = 0;

  while (Serial.available()) {
    char c = Serial.read();
    lastCharTime = millis();

    // 构建响应字符串
    if (responseIndex < MAX_RESPONSE_LENGTH - 1) {
      responseBuffer[responseIndex++] = c;
      responseBuffer[responseIndex] = '\0';
    }

    // 检查是否收到完整响应
    if (strstr(responseBuffer, "\r\nOK\r\n") != NULL || strstr(responseBuffer, "\r\nERROR\r\n") != NULL) {

      processResponse(responseBuffer);

      // 清空缓冲区
      memset(responseBuffer, 0, MAX_RESPONSE_LENGTH);
      responseIndex = 0;
      awaitingResponse = false;
    }
  }

  // 超时处理
  if (awaitingResponse && (millis() - lastCharTime > 5000)) {
    Serial.println("响应超时");
    memset(responseBuffer, 0, MAX_RESPONSE_LENGTH);
    responseIndex = 0;
    awaitingResponse = false;
  }
}

// 处理AT命令响应
void processResponse(char* response) {
  Serial.print("收到响应: ");
  Serial.println(response);

  // 在这里可以添加对特定响应的处理逻辑
  if (strstr(response, "+CMQTTRXMSG:") != NULL) {
    // 解析接收到的MQTT消息
    processMqttMessage(response);
  }
}

// 解析MQTT消息
void processMqttMessage(char* response) {
  // 实际应用中需要根据模块返回格式解析消息内容
  // 这里只是简单示例
  Serial.println("收到MQTT消息");

  // 提取消息内容的逻辑...
}

// 发送AT命令并等待响应
bool sendATCommand(const char* command, const char* expectedResponse, unsigned long timeout) {
  // 等待上一个命令完成
  while (awaitingResponse) {
    handleSerialResponses();
    delay(10);
  }


  // 发送命令
  Serial.println(command);

  // 设置等待响应状态
  awaitingResponse = true;
  currentCommand = command;

  // 等待响应
  unsigned long startTime = millis();
  while (awaitingResponse && (millis() - startTime < timeout)) {
    handleSerialResponses();
    delay(10);
  }

  // 检查响应
  if (!awaitingResponse) {
    // 检查是否包含预期响应
    if (strstr(responseBuffer, expectedResponse) != NULL) {
      return true;
    }
  }

  return false;
}