#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

String ssid = "webserver";            //这里改成你的WIFI名
String wifipasswd = "www.360xyz.cn";  //这里你的WIFI密码
#define DHT11_DATA_PIN 26
#define DHTTYPE DHT11
DHT dht(DHT11_DATA_PIN, DHTTYPE);

WiFiClient espClient;
PubSubClient client(espClient);
const char* mqttServer = "bemfa.com";
const int mqttPort = 9501;
const char* mqttUser = "test";
const char* mqttPassword = "abcdefg";
const char* mqttClientId = "07b120062a7972cf9831d7d9bc8012bc";
const char* mqttTopic = "test";


#define Serial Serial
#define L 25  //LED指示灯引脚
struct
{
  char GPS_Buffer[80];
  bool isGetData;      //是否获取到GPS数据
  bool isParseData;    //是否解析完成
  char UTCTime[11];    //UTC时间
  char latitude[11];   //纬度
  char N_S[2];         //N/S
  char longitude[12];  //经度
  char E_W[2];         //E/W
  bool isUsefull;      //定位信息是否有效
} Save_Data;
const unsigned int gpsRxBufferLength = 600;
char gpsRxBuffer[gpsRxBufferLength];
unsigned int ii = 0;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(L, OUTPUT);
  digitalWrite(L, LOW);
  WiFi.begin(ssid.c_str(), wifipasswd.c_str());
  delay(500);
  WiFi.mode(WIFI_STA);

  while (true) {
    delay(500);
    Serial.print(" . ");
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("flash connet success");
      break;
    }
  }
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
  while (!client.connected()) {
    Serial.println("正在连接MQTT");
    if (client.connect(mqttClientId, mqttUser, mqttPassword)) {
      Serial.println("正在连接MQTT成功");
      client.subscribe(mqttTopic);
    } else {
      Serial.println("正在连接MQTT失败");
      delay(5000);
    }
  }
  Save_Data.isGetData = false;
  Save_Data.isParseData = false;
  Save_Data.isUsefull = false;
  dht.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}
void callback(char* topic, byte* payload, unsigned int length) {
  //Serial.println(topic);
  String msg = "";
  for (int i = 0; i < length; i++) {
    msg += (char)payload[i];
  }
  Serial.print("Msg:");
  Serial.println(msg);
  if (msg == "温湿度") {
    float h = dht.readHumidity();
    float t = dht.readTemperature();
    if (isnan(h) || isnan(t)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      msg = "";
      return;
    }

    Serial.print(F("Humidity: "));
    Serial.print(h);
    Serial.print(F("%  Temperature: "));
    Serial.print(t);
    Serial.print(F("°C "));
    String tmp = String(t) + " °C " + String(h) + "%";
    client.publish(mqttTopic, tmp.c_str());
  }
  if (msg == "定位") {
    gpsRead();         //获取GPS数据
    parseGpsBuffer();  //解析GPS数据
    printGpsBuffer();  //输出解析后的数据
    msg = "";
    return;
  }
  msg = "";
}
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(mqttClientId)) {
      Serial.println("connected");
      Serial.print("subscribe:");
      Serial.println(mqttTopic);
      //订阅主题，如果需要订阅多个主题，可发送多条订阅指令client.subscribe(topic2);client.subscribe(topic3);
      client.subscribe(mqttTopic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


////////////
void errorLog(int num) {
  Serial.print("ERROR");
  Serial.println(num);
  while (1) {
    digitalWrite(L, HIGH);
    delay(300);
    digitalWrite(L, LOW);
    delay(300);
  }
}

void printGpsBuffer() {
  if (Save_Data.isParseData) {
    Save_Data.isParseData = false;

    Serial.print("Save_Data.UTCTime = ");
    Serial.println(Save_Data.UTCTime);

    if (Save_Data.isUsefull) {
      Save_Data.isUsefull = false;
      Serial.print("Save_Data.latitude = ");
      Serial.println(Save_Data.latitude);
      Serial.print("Save_Data.N_S = ");
      Serial.println(Save_Data.N_S);
      Serial.print("Save_Data.longitude = ");
      Serial.println(Save_Data.longitude);
      Serial.print("Save_Data.E_W = ");
      Serial.println(Save_Data.E_W);
      String temp = "Save_Data.latitude = " + String(Save_Data.latitude) + "Save_Data.N_S = " + String(Save_Data.N_S) + "Save_Data.longitude = " + String(Save_Data.longitude) + "Save_Data.E_W = " + String(Save_Data.E_W);
      Serial.println(temp);
      client.publish(mqttTopic, temp.c_str());
    } else {
      Serial.println("GPS DATA is not usefull!");
    }
  }
}

void parseGpsBuffer() {
  char* subString;
  char* subStringNext;
  if (Save_Data.isGetData) {
    Save_Data.isGetData = false;
    Serial.println("**************");
    Serial.println(Save_Data.GPS_Buffer);


    for (int i = 0; i <= 6; i++) {
      if (i == 0) {
        if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
          errorLog(1);  //解析错误
      } else {
        subString++;
        if ((subStringNext = strstr(subString, ",")) != NULL) {
          char usefullBuffer[2];
          switch (i) {
            case 1: memcpy(Save_Data.UTCTime, subString, subStringNext - subString); break;    //获取UTC时间
            case 2: memcpy(usefullBuffer, subString, subStringNext - subString); break;        //获取UTC时间
            case 3: memcpy(Save_Data.latitude, subString, subStringNext - subString); break;   //获取纬度信息
            case 4: memcpy(Save_Data.N_S, subString, subStringNext - subString); break;        //获取N/S
            case 5: memcpy(Save_Data.longitude, subString, subStringNext - subString); break;  //获取纬度信息
            case 6: memcpy(Save_Data.E_W, subString, subStringNext - subString); break;        //获取E/W

            default: break;
          }

          subString = subStringNext;
          Save_Data.isParseData = true;
          if (usefullBuffer[0] == 'A')
            Save_Data.isUsefull = true;
          else if (usefullBuffer[0] == 'V')
            Save_Data.isUsefull = false;

        } else {
          errorLog(2);  //解析错误
        }
      }
    }
  }
}


void gpsRead() {
  while (Serial.available()) {
    gpsRxBuffer[ii++] = Serial.read();
    if (ii == gpsRxBufferLength) clrGpsRxBuffer();
  }

  char* GPS_BufferHead;
  char* GPS_BufferTail;
  if ((GPS_BufferHead = strstr(gpsRxBuffer, "$GPRMC,")) != NULL || (GPS_BufferHead = strstr(gpsRxBuffer, "$GNRMC,")) != NULL) {
    if (((GPS_BufferTail = strstr(GPS_BufferHead, "\r\n")) != NULL) && (GPS_BufferTail > GPS_BufferHead)) {
      memcpy(Save_Data.GPS_Buffer, GPS_BufferHead, GPS_BufferTail - GPS_BufferHead);
      Save_Data.isGetData = true;

      clrGpsRxBuffer();
    }
  }
}

void clrGpsRxBuffer(void) {
  memset(gpsRxBuffer, 0, gpsRxBufferLength);  //清空
  ii = 0;
}
