The use of the ESP8266 in the world of IoT

User avatar
By mrlightsman
#82150 I am thoroughly confused with my sketch. It is very sloppy and poorly coded, but the best I could come up with. Please bear with me.

I am trying to have softAP run so a user can enter the credentials for wifiMulti to work when the ESP restarts.

I have the void setup checking to see if variable SSID1 is empty. If not empty, it runs void setupWifi(), using wifi.multi. That works. If SSID1 is empty, it runs void setupAP() and sets up a softAP. This is where I am broken.

When in softAP mode, serial monitor shows IP as 192.168.4.1. However, when I try to connect to it, my iphone says the ip is 169.254.122.155 with subnet mask 255.255.0.0. No router is shown.

Here are the relavent bits of code:
Code: Select allvoid setupAP(){
  //  WiFi.mode(WIFI_AP);
  Serial.println("");
  Serial.print("Configuring access point...");
  WiFi.softAP("ap_SSID");
  IPAddress myIP = WiFi.softAPIP();
  Serial.println("AP IP address: ");
  Serial.println(myIP);
  chipIp = "Device IP is: ";
  IPAddress chipip = WiFi.localIP();
  String ipString = String(chipip[0]) + '.' + String(chipip[1]) + '.' + String(chipip[2]) + '.' + String(chipip[3]);
  chipIp +=ipString;
}

void setupWifi() {
//  WiFi.mode(WIFI_AP_STA);
  aptime = millis();
  wifiMulti.addAP(SSID1, PW1);
  wifiMulti.addAP(SSID2, PW2);
  wifiMulti.addAP(SSID3, PW3);
  wifiMulti.addAP(SSID4, PW4);

  Serial.println("Connecting Wifi...");
  while (wifiMulti.run() != WL_CONNECTED) {
      if (millis()-aptime >= apdelay) {
        Serial.println("Network Failed. Starting AP Mode.");
        break;
      }
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("Connected to SSID: ");
  Serial.println(WiFi.SSID());
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  chipIp = "Device IP is: ";
  IPAddress chipip = WiFi.localIP();
  String ipString = String(chipip[0]) + '.' + String(chipip[1]) + '.' + String(chipip[2]) + '.' + String(chipip[3]);
  chipIp +=ipString;
}


And, here is the entire code for context. I cannot figure out what I have done to casue softAP to not work correctly. I have spent hours on this and can't figure it out. Any help is appreciated. Thank you.
Code: Select all#include <FS.h>
#include <arduino.h>
#include <WebSocketsClient.h>
#include <WiFiUDP.h>
#include <avdweb_Switch.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>

WebSocketsClient webSocket;
WiFiUDP Udp;
ESP8266WiFiMulti wifiMulti;
ESP8266WebServer server(80);

#define API_ENDPOINT "http://sinric.com"
#define HEARTBEAT_INTERVAL 300000 // 5 Minutes

String webPage; //to store html code from htmlpage

//Switch Contols variables
const byte GPIO_2 = 2; //To control local Device 1
const byte GPIO_0 = 0; //To control local Device 2
const byte RX = 3;  //To manually toggle devices 1&3
const byte TX = 1;  //To manually toggle devices 2&4
int GPIO_2State; //State of local device 1
int GPIO_0State; //State of local device 2
int txState; //digital read of pin to check for reset
int rxState; //digital read of pin to check for reset

//Define UDP server variables
char udp_port[6]; //used to store in json the udp port from user input on WiFi Manager page
unsigned int udpPort;  // used by udp.begin()command (it is udpPort converted for use)
char pktBuf[25]; //buffer for UDP packets

//Define WifiMulti Variables;
char SSID1[16] = "";
char SSID2[16] = "SSID2";
char SSID3[16] = "SSID3";
char SSID4[16] = "SSID4";
char PW1[16] = "Reilly.70";
char PW2[16] = "PW2";
char PW3[16] = "PW3";
char PW4[16] = "PW4";
 
//Define the local IP variables
char ap_SSID[16] = "New_Box"; //SSID for ESP when in AP mode
char ap_Password[16] = "password";          //Password for ESP when in AP mode
unsigned long aptime;  //time wifi first tried to connect to network
unsigned int apdelay = 10000; //how long to delay before giving up on wifi and starting AP mode (10 seconds)
unsigned long lostTime; //time wifi first disconnects from network
unsigned long lostDelay = 300000;  //how long to wait before giving up on reconnect and starting AP mode (5 minutes)
String chipMac = "Device MAC address is: " + String(WiFi.macAddress());
String chipIp;

//Set up UDP variables for WiFIManager
char A_Click_IP[16]=""; // UDP target IP 3
char B_Click_IP[16]=""; // UDP target IP 3
char A_doubleClick_IP[16]=""; // UDP target IP 3
char B_doubleClick_IP[16]=""; // UDP target IP 4
char targetIP[16];

//Define the Alexa variables
char api_key[37]=""; //Sinric API Key
char Local_Device_One[25]=""; // local device 1
char Device_One[25]="Local Device One"; //Device 1 Label
char Local_Device_Two[25]=""; // local device 2
char Device_Two[25]="Local Device Two"; //Device 2 label
char A_Click_Device[25]=""; //alexa device 1
char A_Click[25]="A Click"; // button label
char B_Click_Device[25]=""; //alexa device 2
char B_Click[25]="B Click"; //button label
char A_doubleClick_Device[25]=""; // alexa device 3
char A_doubleClick[25]="A Double Click"; //button label
char B_doubleClick_Device[25]=""; // alexa device 4
char B_doubleClick[25]="B Double Click"; //button label

//set up button debounce with Switch
//Switch RXState = Switch(RX); //button to ground
//Switch TXState = Switch(TX); //button to ground

//Define Auto-off Timer variables for local devices
char offTime1[7]=""; // auto-off time in minutes
char offTime2[7]=""; // auto-off time in minutes
unsigned int autoff1;
unsigned int autoff2;
unsigned long startTime1; // timer for local device 1
unsigned long startTime2; // timer for local device 2
unsigned long currentTime;
unsigned long period1;
unsigned long period2;


//Define the heartbeat timer variables
uint64_t heartbeatTimestamp = 0; //heartbeat timer reset
bool isConnected = false;


//HTML Header
const char htmlHead[]PROGMEM=R"=====(
<!DOCTYPE html>
<html>
<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
<link rel=\"icon\" href=\"data:,\">
<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial;}
table { border-collapse:collapse; width:35%; margin-left:auto; margin-right:auto; }
th { padding:12px; background-color: #0043af; color: white; }
tr { border:1px solid #ddd; padding:12px; }
tr:hover { background-color: #bcbcbc; }
td { border: none; padding:12px; }
.button {background-color: #195B6A; border: none; color: white; padding: 12px 40px;
text-align: center; font-family: \"Trebuchet MS\", Arial;
text-direction: none; font-size: 30px; margin: 2px; cursor: pointer;}
)=====";

//HTML Buttons
const char htmlButtons[]PROGMEM=R"=====(
<h1>  </h1>
<FORM METHOD="POST"action="/">
<input type="submit" value="Control Devices"style="font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial;">
</form>
<p></p>
<FORM METHOD="POST"action="/setup">
<input type="submit" value="Configure Devices"style="font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial;">
</form>
<p></p>
<FORM METHOD="POST"action="/reset">
<input type="submit" value="Restart Device"style="font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial;">
</form>
)=====";

//HTML Footer
const char htmlFoot[]PROGMEM=R"=====(
</body>
</html>
)=====";


void savejson(){ 
  //save the custom parameters to FS
    Serial.println("saving config");
    DynamicJsonBuffer jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();
    json["ap_SSID"] = ap_SSID;
    json["ap_Password"] = ap_Password;
    json["SSID1"] = SSID1;
    json["PW1"] = PW1;
    json["SSID2"] = SSID2;
    json["PW2"] = PW2;
    json["SSID3"] = SSID3;
    json["PW3"] = PW3;
    json["SSID4"] = SSID4;
    json["PW4"] = PW4;
    json["udp_port"] = udp_port;
    json["api_key"] = api_key;
    json["Local_Device_One"] = Local_Device_One;
    json["Device_One"] = Device_One;
    json["offTime1"] = offTime1;
    json["Local_Device_Two"] = Local_Device_Two;
    json["Device_Two"] = Device_Two;
    json["offTime2"] = offTime2;
    json["A_Click_Device"] = A_Click_Device;
    json["A_Click"] = A_Click;
    json["A_Click_IP"] = A_Click_IP;
    json["A_doubleClick_Device"] = A_doubleClick_Device;
    json["A_doubleClick"] = A_doubleClick;
    json["A_doubleClick_IP"] = A_doubleClick_IP;
    json["B_Click_Device"] = B_Click_Device;
    json["B_Click"] = B_Click;
    json["B_Click_IP"] = B_Click_IP;
    json["B_doubleClick_Device"] = B_doubleClick_Device;
    json["B_doubleClick"] = B_doubleClick;
    json["B_doubleClick_IP"] = B_doubleClick_IP;

        File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }
    json.prettyPrintTo(Serial);
    json.printTo(configFile);
    configFile.close();
    //end save
}

void readjson() {
  if (SPIFFS.exists("/config.json")) {
    //file exists, reading and loading
    Serial.println("reading config file");
    File configFile = SPIFFS.open("/config.json", "r");
    if (configFile) {
      Serial.println("opened config file");
      size_t size = configFile.size();
      // Allocate a buffer to store contents of the file.
      std::unique_ptr<char[]> buf(new char[size]);

      configFile.readBytes(buf.get(), size);
      DynamicJsonBuffer jsonBuffer;
      JsonObject& json = jsonBuffer.parseObject(buf.get());
      json.prettyPrintTo(Serial);
      if (json.success()) {
        Serial.println("\nparsed json");

        strcpy(ap_SSID, json["ap_SSID"]);
        strcpy(ap_Password, json["ap_Password"]);
        strcpy(SSID1, json["SSID1"]);
        strcpy(PW1, json["PW1"]);
        strcpy(SSID2, json["SSID2"]);
        strcpy(PW2, json["PW2"]);
        strcpy(SSID3, json["SSID3"]);
        strcpy(PW3, json["PW3"]);
        strcpy(SSID4, json["SSID4"]);
        strcpy(PW4, json["PW4"]);
        strcpy(udp_port, json["udp_port"]);
        strcpy(api_key, json["api_key"]);
        strcpy(Local_Device_One, json["Local_Device_One"]);
        strcpy(Device_One, json["Device_One"]);
        strcpy(offTime1, json["offTime1"]);
        strcpy(Local_Device_Two, json["Local_Device_Two"]);
        strcpy(Device_Two, json["Device_Two"]);
        strcpy(offTime2, json["offTime2"]);
        strcpy(A_Click_Device, json["A_Click_Device"]);
        strcpy(A_Click, json["A_Click"]);
        strcpy(A_Click_IP, json["A_Click_IP"]);
        strcpy(A_doubleClick_Device, json["A_doubleClick_Device"]);
        strcpy(A_doubleClick, json["A_doubleClick"]);
        strcpy(A_doubleClick_IP, json["A_doubleClick_IP"]);
        strcpy(B_Click_Device, json["B_Click_Device"]);
        strcpy(B_Click,json["B_Click"]);
        strcpy(B_Click_IP, json["B_Click_IP"]);
        strcpy(B_doubleClick_Device, json["B_doubleClick_Device"]);
        strcpy(B_doubleClick,json["B_doubleClick"]);
        strcpy(B_doubleClick_IP, json["B_doubleClick_IP"]);
        //add other variables here

      } else {
        Serial.println("failed to load json config");
      }
      configFile.close();
    }
  }
}


void setupAP(){
  //  WiFi.mode(WIFI_AP);
  Serial.println("");
  Serial.print("Configuring access point...");
  WiFi.softAP("ap_SSID");
  IPAddress myIP = WiFi.softAPIP();
  Serial.println("AP IP address: ");
  Serial.println(myIP);
  chipIp = "Device IP is: ";
  IPAddress chipip = WiFi.localIP();
  String ipString = String(chipip[0]) + '.' + String(chipip[1]) + '.' + String(chipip[2]) + '.' + String(chipip[3]);
  chipIp +=ipString;
}

void setupWifi() {
//  WiFi.mode(WIFI_AP_STA);
  aptime = millis();
  wifiMulti.addAP(SSID1, PW1);
  wifiMulti.addAP(SSID2, PW2);
  wifiMulti.addAP(SSID3, PW3);
  wifiMulti.addAP(SSID4, PW4);

  Serial.println("Connecting Wifi...");
  while (wifiMulti.run() != WL_CONNECTED) {
      if (millis()-aptime >= apdelay) {
        Serial.println("Network Failed. Starting AP Mode.");
        break;
      }
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("Connected to SSID: ");
  Serial.println(WiFi.SSID());
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  chipIp = "Device IP is: ";
  IPAddress chipip = WiFi.localIP();
  String ipString = String(chipip[0]) + '.' + String(chipip[1]) + '.' + String(chipip[2]) + '.' + String(chipip[3]);
  chipIp +=ipString;
}


  //if a udp command or button push is detected, toggle the appropriate device
void toggle(String device_Id) {
  if (device_Id == (Local_Device_One)) {
    GPIO_2State = digitalRead(GPIO_2);
    GPIO_2State = !GPIO_2State;
    digitalWrite(GPIO_2, GPIO_2State);
    startTime1 = millis();

  } else if (device_Id == (Local_Device_Two)) {
    GPIO_0State = digitalRead(GPIO_0);
    GPIO_0State = !GPIO_0State;
    digitalWrite(GPIO_0, GPIO_0State);
    startTime2 = millis();
  }
  device_Id = ""; 
}


void process(String target_Id, IPAddress targetIP) {
 if (target_Id == (Local_Device_One)) {
    String device_Id = (Local_Device_One);

    toggle(device_Id);
 } else if (target_Id == (Local_Device_Two)) {
    String device_Id = (Local_Device_Two);
    toggle(device_Id); 
  } else {
    char send_Id[25];
    target_Id.toCharArray(send_Id, 25);
    Udp.beginPacket(targetIP, udpPort);
    Udp.write(send_Id);
    Udp.endPacket();
  }
}


  //Alexa "ON" response
void turnOn(String deviceId) {
  if (deviceId == (Local_Device_One)) {  // Device ID of first device 
    Serial.print("Turn on 1st-device id: ");
//    Serial.println(deviceId);
        digitalWrite(GPIO_2, LOW);
        startTime1 = millis();
  } else if (deviceId == (Local_Device_Two)) {  // Device ID of second device
        digitalWrite(GPIO_0, LOW);
        startTime2 = millis();
  }     
}

  //Alexa "OFF" response
void turnOff(String deviceId) {
   if (deviceId == (Local_Device_One)) {  // Device ID of first device 
     Serial.print("Turn off 1st-Device ID: ");
//     Serial.println(deviceId);
        digitalWrite(GPIO_2, HIGH);
        startTime1 = millis();
   } else if (deviceId == (Local_Device_Two)) { // Device ID of second device
        digitalWrite(GPIO_0, HIGH);
        startTime2 = millis();
  }
}


  //Receive and process an Alexa command
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
  switch(type) {
    case WStype_DISCONNECTED:{
      isConnected = false;   
      break;
    case WStype_CONNECTED: {
      isConnected = true;
      }
      break;
    case WStype_TEXT: {
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject((char*)payload);
        String deviceId = json ["deviceId"];     
        String action = json ["action"];

        if(action == "setPowerState") { // Switch or Light
            String value = json ["value"];
            if(value == "ON") {
                turnOn(deviceId);
            } else {
                turnOff(deviceId);
            }
        }
      }
      break;
    case WStype_BIN:
      break;
    }
  }
}


void handleUpdate() {
  String Header(htmlHead);
  String Buttons(htmlButtons);
  String Footer(htmlFoot);
  webPage = Header;
 
  webPage += "</style><body><h1>Your changes to ";
  webPage += ap_SSID;
  webPage += " have been submitted.</h1>";
  webPage += "<p>";
  webPage += chipMac;
  webPage += "</p><p>";
  webPage += chipIp;
  webPage += "<p></p>";
  webPage += Buttons;
  webPage += Footer;
  server.send(200,"text/html",webPage);
 
  server.arg("custom_ap_SSID").toCharArray(ap_SSID,16);
  server.arg("custom_ap_Password").toCharArray(ap_Password,16);
  server.arg("custom_SSID1").toCharArray(SSID1,15);
  server.arg("custom_PW1").toCharArray(PW1,15);
  server.arg("custom_SSID2").toCharArray(SSID2,15);
  server.arg("custom_PW2").toCharArray(PW2,15);
  server.arg("custom_SSID3").toCharArray(SSID3,15);
  server.arg("custom_PW3").toCharArray(PW3,15);
  server.arg("custom_SSID4").toCharArray(SSID4,15);
  server.arg("custom_PW4").toCharArray(PW4,15);
  server.arg("custom_udp_port").toCharArray(udp_port,6);
  server.arg("custom_api_key").toCharArray(api_key,37);
  server.arg("custom_Local_Device_One").toCharArray(Local_Device_One,25);
  server.arg("custom_Device_One").toCharArray(Device_One,25);
  server.arg("custom_offTime1").toCharArray(offTime1,7);
  server.arg("custom_Local_Device_Two").toCharArray(Local_Device_Two,25);
  server.arg("custom_Device_Two").toCharArray(Device_Two,25);
  server.arg("custom_offTime2").toCharArray(offTime2,7);
  server.arg("custom_A_Click_Device").toCharArray(A_Click_Device,25);
  server.arg("custom_A_Click").toCharArray(A_Click,25);
  server.arg("custom_A_Click_IP").toCharArray(A_Click_IP,16);
  server.arg("custom_A_doubleClick_Device").toCharArray(A_doubleClick_Device,25);
  server.arg("custom_A_doubleClick").toCharArray(A_doubleClick,25);
  server.arg("custom_A_doubleClick_IP").toCharArray(A_doubleClick_IP,16);
  server.arg("custom_B_Click_Device").toCharArray(B_Click_Device,25);
  server.arg("custom_B_Click").toCharArray(B_Click,25);
  server.arg("custom_B_Click_IP").toCharArray(B_Click_IP,16);
  server.arg("custom_B_doubleClick_Device").toCharArray(B_doubleClick_Device,25);
  server.arg("custom_B_doubleClick").toCharArray(B_doubleClick,25);
  server.arg("custom_B_doubleClick_IP").toCharArray(B_doubleClick_IP,16);
  savejson();



void handleConfigureDevice() {
  String Header(htmlHead);
  String Buttons(htmlButtons);
  String Footer(htmlFoot);
  webPage = Header;
 
  webPage += "</style></head><body><h1>";
  webPage += ap_SSID;
  webPage += " Configuration</h1>";
  webPage += "<p>";
  webPage += chipMac;
  webPage += "<p></p>";
  webPage += chipIp;
  webPage += "<p></p>";
  webPage += "<FORM METHOD=\"POST\"action=\"/update\">";
  webPage += "<h3>Access Point Credentials</h3>";
  //AP Setup Table
  webPage += "<table>";
  webPage += "<tr><th>Name</th><td><input type=\"text\" name=\"custom_ap_SSID\" size=\"29\" value=\"";    //ap_SSID
  webPage += ap_SSID;
  webPage += "\"></td></tr>";
  webPage += "<tr><th>Password</th><td><input type=\"text\" name=\"custom_ap_Password\" size=\"29\" value=\"";  //ap_Password
  webPage += ap_Password;
  webPage += "\"></td></tr>";
  webPage += "</table>";
  // Home Network Setup Table
  webPage += "<h3>Home Wifi Settings</h3>";
  webPage += "<table><tr><th></th>";
  webPage += "<th>Wireless Network</th><th>Password</th></tr>";
  webPage += "<tr><td>1</td>";                                           //SSID1
  webPage += "<td><input type=\"text\" name=\"custom_SSID1\" size=\"29\" value=\"";
  webPage += SSID1;
  webPage += "\"></td>";
  webPage += "<td><input type=\"text\" name=\"custom_PW1\" size=\"29\" value=\"";   //PW1
  webPage += PW1;
  webPage += "\"></td></tr>";
  webPage += "<tr><td>2</td>";                                          //SSID2
  webPage += "<td><input type=\"text\" name=\"custom_SSID2\" size=\"29\" value=\"";
  webPage += SSID2;
  webPage += "\"></td>";
  webPage += "<td><input type=\"text\" name=\"custom_PW2\" size=\"29\" value=\"";   //PW2
  webPage += PW2;
  webPage += "\"></td></tr>";
  webPage += "<tr><td>3</td>";                                          //SSID3
  webPage += "<td><input type=\"text\" name=\"custom_SSID3\" size=\"29\" value=\"";
  webPage += SSID3;
  webPage += "\"></td>";
  webPage += "<td><input type=\"text\" name=\"custom_PW3\" size=\"29\" value=\"";   //PW3
  webPage += PW3;
  webPage += "\"></td></tr>";
  webPage += "<tr><td>4</td>";                                           //SSID4
  webPage += "<td><input type=\"text\" name=\"custom_SSID4\" size=\"29\" value=\"";
  webPage += SSID4;
  webPage += "\"></td><td>";
  webPage += "<input type=\"text\" name=\"custom_PW4\" size=\"29\" value=\"";     //PW4
  webPage += PW4;
  webPage += "\"></td></tr>";
  webPage += "</table>";
  //Interconnect Setup Table
  webPage += "<h3>Interconnect Settings<h3>";
  webPage += "<table>";
  webPage += "<tr><th>Interconnect</th><td><input type=\"text\" name=\"custom_udp_port\" size=\"12\" value=\""; // udp_port
  webPage += udp_port;
  webPage += "\"></td></tr>";
  webPage += "<tr><th>API Key</th><td><input type=\"text\" name=\"custom_api_key\" size=\"41\" value=\"";  //api_key
  webPage += api_key;
  webPage += "\"></td></tr>";
  webPage += "</table>";
  //Device Configuration Table
  webPage += "<h3>Device Setting</h3>";
  webPage += "<table>";
  webPage += "<tr><th>Device One</th><td><input type=\"text\" name=\"custom_Local_Device_One\" size=\"29\" value=\""; //Local_Device_One
  webPage += Local_Device_One;
  webPage += "\"></td>";
  webPage += "<th>Name</th><td><input type=\"text\" name=\"custom_Device_One\" size=\"29\" value=\""; //Local_Device_One label
  webPage += Device_One;
  webPage += "\"></td>";
  webPage += "<th>Timer</th><td><input type=\"text\" name=\"custom_offTime1\" size=\"29\" value=\"";                  //offTime1
  webPage += offTime1;
  webPage += "\"></td></tr>";
  webPage += "<tr><th>Device Two</th><td><input type=\"text\" name=\"custom_Local_Device_Two\" size=\"29\" value=\""; //Local_Device_Two
  webPage += Local_Device_Two;
  webPage += "\"></td>";
  webPage += "<th>Name</th><td><input type=\"text\" name=\"custom_Device_Two\" size=\"29\" value=\""; //Local_Device_Two label
  webPage += Device_Two;
  webPage += "\"></td>";
  webPage += "<th>Timer</th><td><input type=\"text\" name=\"custom_offTime2\" size=\"29\" value=\"";                  //offTime2
  webPage += offTime2;
  webPage += "\"></td></tr>";
  webPage += "<tr><th>A Click</th><td><input type=\"text\" name=\"custom_A_Click_Device\" size=\"29\" value=\"";      //A_Click_Device
  webPage += A_Click_Device;
  webPage += "\"></td>";
  webPage += "<th>Name</th><td><input type=\"text\" name=\"custom_A_Click\" size=\"29\" value=\""; // A Click Label
  webPage += A_Click;
  webPage += "\"></td>";
  webPage += "<th>IP</th><td><input type=\"text\" name=\"custom_A_Click_IP\" size=\"29\" value=\"";                   //A_Click_IP
  webPage += A_Click_IP;
  webPage += "\"></td></tr>";
  webPage += "<tr><th>A Double Click</th><td><input type=\"text\" name=\"custom_A_doubleClick_Device\" size=\"29\" value=\""; //A_doubleClick_Device
  webPage += A_doubleClick_Device;
  webPage += "\"></td>";
  webPage += "<th>Name</th><td><input type=\"text\" name=\"custom_A_doubleClick\" size=\"29\" value=\""; // A doubleClick Label
  webPage += A_doubleClick;
  webPage += "\"></td>";
  webPage += "<th>IP</th><td><input type=\"text\" name=\"custom_A_doubleClick_IP\" size=\"29\" value=\"";                     //A_doubleClick_IP
  webPage += A_doubleClick_IP;
  webPage += "\"></td></tr>";
  webPage += "<tr><th>B Click</th><td><input type=\"text\" name=\"custom_B_Click_Device\" size=\"29\" value=\"";      //B_Click_Device
  webPage += B_Click_Device;
  webPage += "\"></td>";
  webPage += "<th>Name</th><td><input type=\"text\" name=\"custom_B_Click\" size=\"29\" value=\""; // B Click Label
  webPage += B_Click;
  webPage += "\"></td>";
  webPage += "<th>IP</th><td><input type=\"text\" name=\"custom_B_Click_IP\" size=\"29\" value=\"";                   //B_Click_IP
  webPage += B_Click_IP;
  webPage += "\"></td></tr>";
  webPage += "<tr><th>B Double Click</th><td><input type=\"text\" name=\"custom_B_doubleClick_Device\" size=\"29\" value=\""; //B_doubleClick_Device
  webPage += B_doubleClick_Device;
  webPage += "\"></td>";
  webPage += "<th>Name</th><td><input type=\"text\" name=\"custom_B_doubleClick\" size=\"29\" value=\""; // B doubleClick Label
  webPage += B_doubleClick;
  webPage += "\"></td>";
  webPage += "<th>IP</th><td><input type=\"text\" name=\"custom_B_doubleClick_IP\" size=\"29\" value=\"";                     //B_double_Click_IP
  webPage += B_doubleClick_IP;
  webPage += "\"></td></tr>";
  webPage += "</table>";
  webPage += "<p></p>";
  webPage += "<input type=\"submit\" value=\"Submit Changes\"style=\"font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial;\"></form><p></p>";  //submit configurations
  webPage += Buttons;
  webPage += Footer;
  server.send(200,"text/html",webPage);
}

void handleRoot() {
  String Header(htmlHead);
  String Buttons(htmlButtons);
  String Footer(htmlFoot);
  webPage = Header;
  webPage += "</style><body><h1>";
  webPage += ap_SSID;
  webPage += " Control</h1>";
  webPage += "<p>";
  webPage += chipMac;
  webPage += "<p></p>";
  webPage += chipIp;
  webPage += "<p></p>";
  webPage += "<FORM METHOD=\"POST\"action=\"/A_Click\">";
  webPage += "<input type=\"submit\" style=\"font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial; value=";
  webPage += A_Click;
  webPage += ">";
  webPage += "</form>";
  webPage += "<p></p>";
  webPage += "<FORM METHOD=\"POST\"action=\"/A_doubleClick\">";
  webPage += "<input type=\"submit\" style=\"font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial; value=";
  webPage += A_doubleClick;
  webPage += ">";
  webPage += "</form>";
  webPage += "<p></p>";
  webPage += "<FORM METHOD=\"POST\"action=\"/B_Click\">";
  webPage += "<input type=\"submit\" style=\"font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial; value=";
  webPage += B_Click;
  webPage += ">";
  webPage += "</form>";
  webPage += "<p></p>";
  webPage += "<FORM METHOD=\"POST\"action=\"/B_doubleClick\">";
  webPage += "<input type=\"submit\" style=\"font-size : 35px; width: 50%; height: 100px;font-family: \"Trebuchet MS\", Arial; value=";
  webPage += B_doubleClick;
  webPage += ">";
  webPage += "</form>";
  webPage += Buttons;
  webPage += Footer;
  server.send(200,"text/html",webPage);
}

void handleRestart() {
  String Header(htmlHead);
  String Buttons(htmlButtons);
  String Footer(htmlFoot);
  webPage = Header;
  webPage += "</style><body><h1>";
  webPage += ap_SSID;
  webPage += " restarting. Please wait.</h1>";
  webPage += "<p>";
  webPage += chipMac;
  webPage += "</p><p>";
  webPage += chipIp;
  webPage += "<p></p>";
  webPage += Buttons;
  webPage += Footer;
  server.send(200,"text/html",webPage);
  delay(1000);
  ESP.restart();
}

void handleA_Click() {
  String target_Id = (A_Click_Device);
  IPAddress targetIP;
  targetIP.fromString(A_Click_IP);
  process(target_Id, targetIP);
  handleRoot();
}

void handleA_doubleClick() {
  String target_Id = (A_doubleClick_Device);
  IPAddress targetIP;
  targetIP.fromString(A_doubleClick_IP);
  process(target_Id, targetIP);
  handleRoot();
}

void handleB_Click() {
  String target_Id = (B_Click_Device);
  IPAddress targetIP;
  targetIP.fromString(B_Click_IP);
  process(target_Id, targetIP);
  handleRoot();
}

void handleB_doubleClick() {
  String target_Id = (B_doubleClick_Device);
  IPAddress targetIP;
  targetIP.fromString(B_doubleClick_IP);
  process(target_Id, targetIP);
  handleRoot();
}

void handleNotFound(){
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}


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

  // Setup pins to off position
  pinMode(GPIO_2, OUTPUT);
  digitalWrite(GPIO_2, HIGH);
  pinMode(GPIO_0, OUTPUT);
  digitalWrite(GPIO_0, HIGH);
//  pinMode(RX, INPUT_PULLUP);
//  pinMode(TX, INPUT_PULLUP);

//  SPIFFS.format();  //clean FS, for testing


  //read configuration from FS json
  Serial.println("mounting FS...");
  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    readjson();
  } else {
    Serial.println("failed to mount FS");
  }
  savejson();
  //end read

  if(strlen(SSID1) == 0) {
    setupAP();
  } else {               
  WiFi.setSleepMode(WIFI_NONE_SLEEP);
  setupWifi();
  }
  delay(500);

  server.on("/", handleRoot);
  server.on("/reset", handleRestart);
  server.on("/A_Click", handleA_Click);
  server.on("/A_doubleClick", handleA_doubleClick);
  server.on("/B_Click", handleB_Click);
  server.on("/B_doubleClick", handleB_doubleClick);
  server.on("/setup", handleConfigureDevice);
  server.on("/update",handleUpdate);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP Server Started");
 
  // Alexa server address, port and URL
  webSocket.begin("iot.sinric.com", 80, "/");
  Serial.println("WebSocket started.");

  // Alexa event handler
  webSocket.onEvent(webSocketEvent);
  webSocket.setAuthorization("apikey", api_key);
  // try again every 5000ms if connection has failed
  webSocket.setReconnectInterval(5000);   // If you see 'class WebSocketsClient' has no member named 'setReconnectInterval' error update arduinoWebSockets


  //Start UDP server
  udpPort = atoi(udp_port);
  Udp.begin(udpPort);
  Serial.println("UDP Started");

  //Set up Auto-off Timers
  startTime1 = millis(); //save the start time for device 1
  startTime2 = millis(); //save the start time for device 2
  autoff1 = atoi(offTime1);
  autoff2 = atoi(offTime2);
 
  period1 = (autoff1 * 60000);
  period2 = (autoff2 * 60000);

  if(period1 == 0) {
    period1 = 86400000;
  }

  if (period2 == 0) {
    period2 = 86400000;
  }

  lostTime = millis();

  Serial.println("Loop Started");
} //end void setup()


void loop() {
  server.handleClient();
  webSocket.loop();
//  wifiMulti.run();

//  RXState.poll();
//  TXState.poll();
//  txState = digitalRead(TX);
//  rxState = digitalRead(RX);



  // test wifi connection. If lost try to reconnect
  if (wifiMulti.run() != WL_CONNECTED) {
    if (millis() - lostTime > lostDelay) {
      lostTime = millis();
      setupWifi();
    }
  }

 
  //Receive incoming Udp packet and parse information
  int pktSize = Udp.parsePacket();
  if (pktSize) {
    Udp.read(pktBuf, pktSize);
   }

  String packetbuffer (pktBuf);

  //What to do with Udp packet
  if (packetbuffer.startsWith(Local_Device_One)) {  //Toggle A_Click_Device
      String device_Id = (Local_Device_One);
      toggle(device_Id);
      String packetbuffer = "";
      for (int i = 0; i<25; i++){
        pktBuf[i] = (char) 0;
        }
      Udp.flush();
  }
       
  if (packetbuffer.startsWith(Local_Device_Two)) {  //Toggle B_Click_Device
      String device_Id = (Local_Device_Two);
      toggle(device_Id);
      String packetbuffer = "";
      for (int i = 0; i<25; i++){
        pktBuf[i] = (char) 0;
        }
      Udp.flush(); 
    }
     
    if (packetbuffer.startsWith("reset")) { // invoke AP reset with UDP
       ESP.reset();  //reset and try again, or maybe put it to deep sleep
       delay(3000);   
    }
   
    if (packetbuffer.startsWith("survey")) { // send status update to controller
        Udp.beginPacket(Udp.remoteIP(), udpPort);
        Udp.write(ap_SSID);
        Udp.endPacket();
        for (int i = 0; i<25; i++){
          pktBuf[i] = (char) 0;
          }
        Udp.flush();
    }

  //What to do with button presses
//  if (RXState.singleClick()){
//      String target_Id = (A_Click_Device);
//      IPAddress targetIP;
//      targetIP.fromString(A_Click_IP);
//      process(target_Id, targetIP);
//  }

//  if (RXState.doubleClick()){
//      String target_Id = (A_doubleClick_Device);
//      IPAddress targetIP;
//      targetIP.fromString(A_doubleClick_IP);
//      process(target_Id, targetIP);
//  }
   
//  if (RXState.longPress()) {
//     WiFiManager wifiManager;
//     wifiManager.resetSettings();
//     delay(1000);
//     ESP.restart();  //reset and try again, or maybe put it to deep sleep
//     delay(3000);
//  }
       
//  if (TXState.singleClick()){
//      String target_Id = (B_Click_Device);
//      IPAddress targetIP;
//      targetIP.fromString(B_Click_IP);
//      process(target_Id, targetIP);
//  }

//  if (TXState.doubleClick()){
//      String target_Id = (B_doubleClick_Device);
//      IPAddress targetIP;
//      targetIP.fromString(B_doubleClick_IP);
//      process(target_Id, targetIP); 
//  }
 
//  if (TXState.longPress()) {
//      WiFiManager wifiManager;
//      delay(1000);
//      wifiManager.resetSettings();
//      delay(1000);
//      ESP.restart();  //reset and try again, or maybe put it to deep sleep
//      delay(3000);       
//  }

//  if (txState == LOW) {
//    if (rxState == LOW) {
//      ESP.restart();
//    }
//  }

  //Set timer
  currentTime = millis();

  //Auto-off timer device 1
  if (currentTime - startTime1 >= period1) {
    digitalWrite(GPIO_2, HIGH);
    startTime1 = millis();
  }

  //Auto-off timer device 2
  if (currentTime - startTime2 >= period2) {
    digitalWrite(GPIO_0, HIGH);
    startTime2 = millis();
  }
 
  if(isConnected) {
    uint64_t now = millis();
     
    // Send heartbeat in order to avoid disconnections during ISP resetting IPs over night.
    if((now - heartbeatTimestamp) > HEARTBEAT_INTERVAL) {
      heartbeatTimestamp = now;
      webSocket.sendTXT("H");         
    }
  }

} //end loop