#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#include <FS.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
#include <Ticker.h>
//被读取的文件位置和名称
String flash_wifi = "/wifi.txt";
ESP8266WebServer ESP8266webServer(80);  // 创建网络服务器对象，HTTP服务的标准端口为：80
String ssid = "";
String passwd = "";
String html;
WebSocketsClient webSocket;
Ticker myTicker;
WiFiClient wificlient;
//定时时间防止断电重启后定时失效
String flash_time = "time.txt";
int service_i = 0;
//普通开关
int d0 = 0;
//最近操作物联用户相关信息
String UserExec = "";
String str;
DynamicJsonDocument  jsonBuffer(100);
JsonObject root;

void setup(void) {
  pinMode(d0, OUTPUT);
  digitalWrite(d0, HIGH);
  delay(500);
  if (FlashConnetWifi() == false) {
    HtmlSetWifi();
  }

  //先读取定时数据
  SPIFFS.begin();
  if (SPIFFS.exists(flash_time) == true) {
    File timeFile = SPIFFS.open(flash_time, "r");
    String timef = timeFile.readString();
    //去除前后空格
    timef.trim();
    String flash_t = timef.substring(0, 10);
    String timenow = http_get("http://www.360xyz.cn/query/GetTime");
    int timen = timenow.toInt();
    int flash_ti = flash_t.toInt();
    if ( timen < flash_ti) {
      int ress = flash_ti - timen;
      String on_off = timef.substring(10);
      //等为0为关 1为开
      if (on_off == "0") {
        myTicker.once(ress, closea);
        Serial.println(String(ress) + "定时关");
      } else {
        myTicker.once(ress, opena);
        Serial.println(String(ress) + "定时开");
      }
    }
  }
  webSocket.beginSSL("www.360xyz.cn", 443, "/service/wss");
  webSocket.onEvent(webSocketEvent);
  webSocket.setAuthorization("user=switch1&password=efghijk&room=admin");
  webSocket.setReconnectInterval(500);
  webSocket.enableHeartbeat(15000, 3000, 2);


}

void loop(void) {
  webSocket.loop();

}

void HtmlSetWifi() {
  WifiScan();
  ap_start();
  delay(1000);
  Serial.println("启动网页");
  webserver_start();
  while (1) {
    ESP8266webServer.handleClient();   // 检查网络服务请求并处理
  }
}
//扫描附件WIFI
void WifiScan() {
  Serial.begin(19200);
  WiFi.mode(WIFI_STA);
  delay(100);
  int n = WiFi.scanNetworks();
  if (n > 0) {
    Serial.println(n);
    String a =  "附近WiFi <select id=\"ssid\">";
    for (int i = 0; i < n; i++) {
      Serial.println(WiFi.SSID(i));
      a = a +  "<option value=\"" + WiFi.SSID(i) + "\">" + WiFi.SSID(i) + "</option>";
      delay(50);
    }
    String HtmlStart = String("") + "<!DOCTYPE html>" +
                       "<html>" +
                       "<head>" +
                       "<meta charset=\"utf-8\">" +
                       "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" />" +
                       "<title>设置WiFi</title>" +
                       "<link rel=\"stylesheet\" href=\"\">" +
                       "</head>" +
                       "<script>" +
                       "onload  = function() {" +
                       "document.getElementById(\"up\").onclick = function(){" +
                       "var ssida=document.getElementById(\"ssid\").value;" +
                       "var ssid=ssida.replace(/\\s+/g, \" \");" +
                       "var passwda=document.getElementsByTagName('input')[0].value;" +
                       "var passwd=passwda.replace(/\\s+/g, \" \");" +
                       "xhr = new XMLHttpRequest();" +
                       "xhr.open(\"POST\",\"./set_wifi\",true);" +
                       "var posts = (\"ssid=\"+ssid+\"&passwd=\"+ passwd);" +
                       "xhr.setRequestHeader(\"Content-Type\",\"application/x-www-form-urlencoded\");" +
                       "xhr.send(posts);" +
                       "xhr.onreadystatechange = function(){" +
                       "if(this.readyState == 4 && this.status == 200){" +
                       "alert(this.responseText);" +
                       "}" +
                       "}" +
                       "}" +
                       "}" +
                       "</script>" +
                       "<body>";
    String HtmlEnd = String("") + "<p>WiFi密码<input type=\"text\" id=\"passwd\"></p>" +
                     "<input type=\"submit\" id=\"up\" value=\"设 置\">" +
                     "<hr/>" +
                     "<div>如果附近WiFi没有显示到自己的WIFI<div>" +
                     "<div>请重启或离信号近点</div>" +
                     "<div>连接成功AP热点退出转WIFI_STA</div>" +
                     "</body>" +
                     "</html>";
    a = a +  "</select>";
    html = HtmlStart + a + HtmlEnd;
  } else {
    html = "扫描不到网络";
    Serial.println("扫描不到网络");
  }
}
void set_wifi() {
  ssid = ESP8266webServer.arg(0);
  passwd = ESP8266webServer.arg(1);
  String sp = ssid + "&" + passwd;

  Serial.println(sp);
  Serial.begin(19200);
  delay(500);
  WiFi.begin(ssid, passwd);
  WiFi.mode(WIFI_STA);
  delay(200);
  Serial.println("wifi_connet");
  int ii = 0;
  for (ii; ii < 20; ii++) {
    delay(500);
    Serial.print(".");
    if (WiFi.status() == WL_CONNECTED) {
      ESP8266webServer.send(200, "text/plane", "Wifi密码正确，ESP准备重启");
      ESP8266webServer.close();
      delay(500);
      WiFi.disconnect();
      delay(500);
      //写入数据
      SPIFFS.format();
      delay(500);
      SPIFFS.begin();
      File dataFile = SPIFFS.open(flash_wifi, "w");
      dataFile.println(sp);
      dataFile.close();
      Serial.println("HTML连接成功");
      delay(1000);
      ESP.reset();
    }
  }
  ESP8266webServer.send(200, "text/plane", "Wifi密码错误，请重新输入");
  //HtmlSetWifi();
}
//------- 展示页面-------
void handleRoot() {
  ESP8266webServer.send(500, "text/html", html);
}
void handleNotFound(void) {
  ESP8266webServer.send(404, "text/plain", "404-The page is not Found!");
}


void ap_start() {
  Serial.begin(19200);
  WiFi.mode(WIFI_AP);
  IPAddress local_IP(192, 168, 168, 2);
  IPAddress gateway(192, 168, 168, 1);
  IPAddress subnet(255, 255, 255, 0);
  WiFi.softAPConfig(local_IP, gateway, subnet) ;

  //启动AP模式，并设置账号和密码
  boolean result = WiFi.softAP("192.168.168.2", "192.168.168.2");
  if (result) {
    //输出 soft-ap ip地址
    //Serial.println(String("Soft-AP IP address = ") + WiFi.softAPIP());
  }
}
void webserver_start() {
  //-----------------启动webserver网络服务--------------------
  ESP8266webServer.begin(); // 启用网络服务
  ESP8266webServer.on("/", handleRoot);   // / 在HTTP中，表示请求首页服务，
  ESP8266webServer.on("/set_wifi", set_wifi);
  ESP8266webServer.onNotFound(handleNotFound);    // 当服务器没找到所需的服务，调用404函数
  Serial.println("webserver started");
}

bool FlashConnetWifi() {
  Serial.begin(19200);
  delay(500);
  //是否存在数据
  SPIFFS.begin();
  if (SPIFFS.exists(flash_wifi) == false) {
    Serial.print(flash_wifi);
    Serial.println(" NOT FOUND");
    return false;
  }

  File dateFile = SPIFFS.open(flash_wifi, "r");
  String result;
  for (int i = 0; i < dateFile.size(); i++) {
    //Serial.print((char)dateFile.read());
    result += (char)dateFile.read();
  }
  //去除前后空格
  result.trim();
  Serial.println(result);
  int i = result.indexOf("&");
  String wifiname = result.substring(0, i);
  String wifipw = result.substring(i + 1);
  Serial.println(wifiname);
  Serial.println(wifipw);
  WiFi.begin(wifiname, wifipw);
  delay(500);
  WiFi.mode(WIFI_STA);
  Serial.println("FlashConnetWifi->connet");
  int ii = 0;
  for (ii; ii < 10; ii++) {
    delay(500);
    Serial.print(" . ");
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("FlashConnetWifi 闪存配置连接成功");
      return true;
    }
  }
  Serial.println("FlashConnetWifi->false");
  return false;
}
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
  switch (type) {
    case WStype_DISCONNECTED:
      Serial.printf("[WSc] Disconnected!\n");
      service_i++;
      if (service_i == 200) {
        ESP.reset();
      }
      break;
    case WStype_CONNECTED: {
        Serial.printf("[WSc] Connected to url: %s\n", payload);
        // send message to server when Connected
        webSocket.sendTXT("Connected");
      }
      break;
    case WStype_TEXT:
      Serial.printf("[WSc] get text: %s\n", payload);
      deserializeJson(jsonBuffer, payload);
      root = jsonBuffer.as<JsonObject>();
      if (root["message"] != "") {
        String user = root["user"];
        String date = root["date"];
        String message = root["message"];
        if (root["message"] == "switch1->0") {
          //关
          Serial.println("关");
          webSocket.sendTXT("close ...");
          digitalWrite(d0, HIGH);

          UserExec = user + " -> 关闭 " + date;
        }
        if (root["message"] == "switch1->1") {
          //开
          Serial.println("开");
          webSocket.sendTXT("open ...");
          digitalWrite(d0, LOW);
          String user = root["user"];
          String date = root["date"];
          UserExec = user + " -> 开启 " + date;
        }
        if (root["message"] == "AllState") {
          delay(1000);
          //查看设备是否在线，应做出回应
          if (UserExec == "") {
            webSocket.sendTXT("臣在 定时开启 秒|定时关闭 秒|定时状态|定时取消|reboot");
          } else {
            webSocket.sendTXT(UserExec);
          }
        }
        //秒钟单位 关闭
        if (message.indexOf("switch1->定时关闭") != -1) {
          int alllen = message.length();
          String re = message.substring(21);
          int res = re.toInt();
          myTicker.once(res, closea);
          String timenow = http_get("http://www.360xyz.cn/query/GetTime");
          String timestr = String(timenow.toInt() + res) + "0";
          int timeint = timestr.toInt();
          SPIFFS.begin();
          File dataFile = SPIFFS.open(flash_time, "w");
          dataFile.println(timestr);
          dataFile.close();
          String sendtemp = "定时关 设置成功 " + re + "秒";
          webSocket.sendTXT(sendtemp);
        }

        //秒钟单位 开启
        if (message.indexOf("switch1->定时开启") != -1) {
          int alllen = message.length();
          String re = message.substring(21);

          int res = re.toInt();
          myTicker.once(res, opena);
          String timenow = http_get("http://www.360xyz.cn/query/GetTime");
          String timestr = String(timenow.toInt() + res) + "1";
          int timeint = timestr.toInt();
          SPIFFS.begin();
          File dataFile = SPIFFS.open(flash_time, "w");
          dataFile.println(timestr);
          dataFile.close();
          String sendtemp = "定时开 设置成功 " + re + "秒";
          webSocket.sendTXT(sendtemp);
        }

        if (root["message"] == "switch1->定时状态") {
          bool b = myTicker.active();
          if (b == true) {
            webSocket.sendTXT("定时正在启用");
          } else {
            webSocket.sendTXT("定时未启用");
          }
        }
        if (root["message"] == "switch1->定时取消") {
          myTicker.detach();
          SPIFFS.begin();
          File dataFile = SPIFFS.open(flash_time, "w");
          dataFile.println(123123123);
          dataFile.close();
          webSocket.sendTXT("定时已经取消");
        }
        if (root["message"] == "switch1->reboot") {
          ESP.reset();
        }
      }

      break;
    case WStype_BIN:
      Serial.printf("[WSc] get binary length: %u\n", length);
      hexdump(payload, length);

      // send data to server
      // webSocket.sendBIN(payload, length);
      break;
    case WStype_PING:
      // pong will be send automatically
      Serial.printf("[WSc] get ping\n");
      break;
    case WStype_PONG:

      Serial.printf("[WSc] get pong\n");
      break;
  }
}
void closea() {
  Serial.println("switch1定时触发 关");
  digitalWrite(d0, HIGH);
  delay(500);
  //取消定时状态
  myTicker.detach();
  delay(500);
  http_get("http://www.360xyz.cn/service/SendEmail?title=switch1->定时关闭|-s");
}
void opena() {
  Serial.println("switch1定时触发 开");
  digitalWrite(d0, LOW);
  delay(500);
  //取消定时状态
  myTicker.detach();
  delay(500);
  http_get("http://www.360xyz.cn/service/SendEmail?title=switch1->定时开启|-s");
}


String http_get(String string) {
  HTTPClient http;
  String response;
  http.begin(wificlient, string);
  http.setTimeout(3000);
  int httpCode = http.GET();
  // httpCode will be negative on error
  if (httpCode == 200) {
    response = http.getString();
    return response;
  } else {
    return "";
  }
  http.end();
}