esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.07k stars 13.33k forks source link

Random WDT Reset with low WiFI Signal #4942

Closed vangalvin closed 6 years ago

vangalvin commented 6 years ago

Basic Infos

Platform

Settings in IDE

Problem Description

I have been chasing some random WDT issues for about a week and it appears that the problem is caused when you have a really low WiFi signal or an unstable connection. My one was running at levels in the -83 down to -91 at times, I was not expecting it to even work that low but to my surprise what seems to happen is the WDT triggers a reboot.

I was receiving both of these at various times. The only error i seem to be getting is

ets Jan 8 2013,rst cause:4, boot mode:(1,7) wdt reset

ets Jan 8 2013,rst cause:4, boot mode:(1,6) wdt reset

I did have a few stack dumps however I was not able to get them converted using the exception decider for some reason and since moving the Nodemcu I don't seem to have received any more.

Initial thought were it may have been caused by power issues, I have installed a 3.3v supply with a 1000uf cap and know the supply will quite happily deliver up to about 2A so that should be more than enough. In addition the control systems for the Fan etc have been optically isolated just to be sure that there were no feedback issues.

The code for this project is quite sizable and has bits all over the place at the moment as it is a work in progress so please keep that in mind. :)

C Sketch

// include the lib's for the File System
#include <FS.h>
#include <ArduinoJson.h>

// Include the libs for the Sensors
#include "DHTesp.h"
#include <OneWire.h>
#include <DallasTemperature.h>

// Include the lib's for timer related stuff
#include <Time.h>
#include <TimeLib.h>
#include <Ticker.h>

// Include the lib's for WiFi
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>

// Include the lib's for PID Controll
#include <PID_v1.h>
#include <PID_AutoTune_v0.h>

//Include Other libs
#include <math.h>

// Set up the ticke's for the various timed routines
Ticker prn;                         //Ticler for the print to serial port
Ticker udtemp;                      //Ticker to read and update the temperature from the Dallas 1 wire sensors
Ticker doPID;                       //Ticker for the PID controll of Fan and Heater
Ticker prnLog;                      //Ticker to Print and Output the log
Ticker DHTSensor;                   //Ticker to Read the DHT Sensor

//IPAddress    apIP(192, 168, 4, 1);  // Defining a static IP address: local & gateway

// ESSID and Password of the WiFi Access Point to connect to, and Set out Hostname.
//const char *ssid = "ESP8266";
//const char *password = "testesp1";
//const char *host = "Cloche-Heater";

const char *ssid = "ESP8266";               //If this device is set up as an AP this is the ESSID
const char *password = "testesp1";          //If this device is set up as an AP this is the password
const char *host = "Cloche-Heater";         //Host Name of this device
const char *apid = "MyESSID";          //ESSID of the AP to connect to
const char *appass = "MyPassword";          //Password of the AP to connect to

// Define a web server at port 80 for HTTP
ESP8266WebServer server(80); 
ESP8266HTTPUpdateServer httpUpdater;

// Define the pins used for the sensors and controll's
#define FAN D5                                        //PWM Fan Pin
#define HEATER D6                                     //PWM Heater Pin
#define TEMPERATURE_BUS D4                            //Dallas 1 wire Temperature Sensors
#define TEMPERATURE_PRECISION 12                      //Dallas 1 wire Temperature Sensor Precision
#define SOILSENS A0                                   //Analog pin for Soil Moisture Sensor
#define DHT_PIN D1                                    //DHT Humidity/Temperature Sensor

//If we are going to update set this to 1 and halt all other processes.
bool OTAupdate = 0;

//int nowTime;

//int opperation = 0;   //0=normal run, 1=calibrate heater, 2=calibate fan

int fanspeed = 21;
double SetpointA, InputA, OutputA;
double Sensor[3];
double iTemp, oTemp, gTemp;
double tempDiff = 5;

int soilmoisture;
int drysoil = 840;
int water = 0;
bool setDiff = 0;
bool logToFile = 0;

//double Kp=32, Ki=0.5, Kd=0.5;
//double Kp=600, Ki=100, Kd=0.7;
double Kp=600, Ki=0.5, Kd=0.5;

OneWire oneWire(TEMPERATURE_BUS);

PID PIDa(&InputA, &OutputA, &SetpointA, Kp, Ki, Kd, DIRECT);

File Logfile;

//Structure of the Soil Sensor readings
struct SoilSensor {
  int moisture;
  int dry = 840;
  int sat = 0;
};

// Configuration that we'll store on disk
struct Config {
  bool fileLogStatus;       // The satatus of our Logging Function
  int tempDiffValue;        // The temperature diference between the Inside and Outside probes
};

const char *filename = "/config.txt";  // File to store the config in
Config config;                         // global configuration object

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
DeviceAddress Sensor0 = { 0x28, 0x5A, 0x82, 0x23, 0x17, 0x13, 0x01, 0x98 };   //Address for Sensor1 Outside the cabinet
DeviceAddress Sensor1 = { 0x28, 0xEB, 0x09, 0x2F, 0x17, 0x13, 0x01, 0x01 };   //Address for Sensor2 Ground Temperature
DeviceAddress Sensor2 = { 0x28, 0xFB, 0x03, 0xBE, 0x16, 0x13, 0x01, 0x22 };   //Address for Sensor3 Inside the cabinet

DHTesp dht;
bool getDHT = false;
float humidity;
float temperature;
void dhtTicker() {
  getDHT = true;
}

const int ledPin = D4; // an LED is connected to NodeMCU pin D1 (ESP8266 GPIO5) via a 1K Ohm resistor
bool ledState = false;
bool consoleLog = true;
bool fileLog = false;

void handleRoot() {
 String s = MAIN_page; //Read HTML contents
 server.send(200, "text/html", s); //Send web page
}

void handleDiffChange(){
  if (server.args() > 0 ) {
    for ( uint8_t i = 0; i < server.args(); i++ ) {
      if (server.argName(i) == "diff") {
         // do something here with value from server.arg(i);
         String diff = server.arg(i);
         tempDiff = diff.toFloat();
         config.fileLogStatus = fileLog;
         config.tempDiffValue = tempDiff;
         Serial.println("Settings Changed, Saving to Config File");
         saveConfiguration(filename, config);   //diffrential temperature change so save new value to config
         server.send(200, "text/plain", String(tempDiff)); //Send Temperature Offset value only to client ajax request

//         handleRoot();
      }
   }
}
}
// Send the temperature and Sensor data to the Wireless Client
void sendTempUpdate(){
  String message;
  message = String(Sensor[0]); //Outside Temperature
  message +="|";
  message += String(Sensor[1]); //Ground Temperature
  message +="|";
  message += String(Sensor[2]); //Inside Temperature
  message +="|";
  message += String(tempDiff);  //Temperature Differential
  message +="|";
  message += String(setDiff); //Server Handshake for settings
  message +="|";
  message += String(soilmoisture);  //Moisture content of the soil
  message +="|";
  message += String(humidity);  //Reletive Humidity
//  message +="|";
//  message += String(logToFile);
  server.send(200, "text/plain", String(message));
}

void handleNotFound() {
  //digitalWrite ( LED_BUILTIN, 0 );
  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 );
  //digitalWrite ( LED_BUILTIN, 1 ); //turn the built in LED on pin DO of NodeMCU off
}

void calculatePID(){
    InputA = Sensor[2];
    SetpointA = Sensor[0] + tempDiff;
    PIDa.Compute();
    fanspeed = map(OutputA, 0, 1024, 45, 300);
    analogWrite(FAN, (int)fanspeed);
    analogWrite(HEATER, (int)OutputA);
    soilmoisture = analogRead(SOILSENS);
    }

void updateTemperature(){
  sensors.requestTemperatures();
  Sensor[0] = sensors.getTempC(Sensor0);
  oTemp = Sensor[0];
  Sensor[1] = sensors.getTempC(Sensor1);
  gTemp = Sensor[1];
  Sensor[2] = sensors.getTempC(Sensor2);
  iTemp = Sensor[2];
}

void printToLog(){
  String prnLogMsg;
  int nowTime = now();
    prnLogMsg = String(now());
    prnLogMsg += ", t1:";
    prnLogMsg += Sensor[0];
    prnLogMsg += ", t2:";
    prnLogMsg += Sensor[1];
    prnLogMsg += ", t3:";
    prnLogMsg += Sensor[2];
    prnLogMsg += ", h:";
    prnLogMsg += (int)OutputA;
    prnLogMsg += ", f:";
    prnLogMsg += (int)fanspeed;
    prnLogMsg += ", s:";
    prnLogMsg += soilmoisture;
    //prnLogMsg += (int)soilmoisture;
    prnLogMsg += ", h:";
    prnLogMsg += humidity;
    //prnLogMsg += (int)humidity;
    prnLogMsg += "\n";
    if(consoleLog){      //Log to console if this is set
    Serial.print(prnLogMsg);
    }
    if(fileLog){        //Log to File if this is set
        Logfile = SPIFFS.open("/ClocheLog.csv", "a"); // this opens the file in append-mode
        if (!Logfile) {
            Serial.println("File doesn't exist yet");
        }
        Logfile.print(prnLogMsg);
        Logfile.close();
    }
}

long stringToLong(String s){
   char arr[32];
   s.toCharArray(arr, sizeof(arr));
   return atol(arr);
}

void setLocalTime(){
    if (server.args() > 0 ) {
      if (server.argName(0) == "hr") {
         //setTime(hr,min,sec,day,month,yr);
         Serial.println(server.arg(0).toInt());
         Serial.println(server.arg(1).toInt());
         Serial.println(server.arg(2).toInt());
         setTime(server.arg(0).toInt(), server.arg(1).toInt(),server.arg(2).toInt(), server.arg(3).toInt(), server.arg(4).toInt(), server.arg(5).toInt());  
         // do something here with value from server.arg(i);
         Serial.print(" Time Set to: ");
         long thisTime = now();
         Serial.print(thisTime);
         Serial.print(" ");
         Serial.print(hour(thisTime));
         Serial.print(":");
         Serial.print(minute(thisTime));
         Serial.print(":");
         Serial.print(second(thisTime));
         Serial.print(" ");
         Serial.print(day(thisTime));
         Serial.print("/");
         Serial.print(month(thisTime));
         Serial.print("/");
         Serial.println(year(thisTime));

         //setTime(123445);
         server.send(200, "text/plain", "Time Set"); //Send Temperature Offset value only to client ajax request
      }
    }  
}

void prepUpdate(){
    Serial.print("Preparing for Firmare Update");
    //Detatch the timers prior to the update
    prnLog.detach();
    udtemp.detach();
    doPID.detach();
    //Send a message to the user with a redirect to the page
    server.send(200, "text/html", "<head><meta http-equiv=\"refresh\" content=\"5;url=/update\"></head><body>Please wait while Firmware Update Page is loaded<br> Or <a href=\"/update\">Click here if page does not automaticly refresh</a></body>");
    //Close and Stop the web server
    server.close();
    server.stop();
    //Initiate the Web Update Server
    httpUpdater.setup(&server);
    //Restart the server
    server.begin();
}

void logData(){
  //Activate or Deactivate Logging to file.
  String message;
    if (server.args() > 0 ) {
    for ( uint8_t i = 0; i < server.args(); i++ ) {
      if (server.argName(i) == "LogStatus"){
        Serial.println("LogStatus Requested");
        message = config.fileLogStatus;
        message += "|";
        message += config.tempDiffValue;
        message += "\n";
        //server.send(200, "text/plain", message);
      }
      if (server.argName(i) == "logcmd") {
         setTime(server.arg(1).toInt(), server.arg(2).toInt(),server.arg(3).toInt(), server.arg(4).toInt(), server.arg(5).toInt(), server.arg(6).toInt());
         // request received to start or stop log;
         String LogStatus = server.arg(i);
         if(LogStatus == "ON"){
          //start logging
          Serial.println("Logging to File ON");
          fileLog = true;
          prnLog.attach(10, printToLog); //output the data ever 10 seconds
          message = "ON";
          //server.send(200, "text/plain", "ON");
         }
         if(LogStatus == "OFF"){
          //stop logging
          Serial.println("Logging to File OFF");
          fileLog = false;
          startSPIFFS();
          prnLog.detach();
          message = "OFF";
          //server.send(200, "text/plain", "OFF");
         }
//         server.send(200, "text/plain", "OK");
      }
   }
}
server.send(200, "text/plain", message);  //send message back to client
config.fileLogStatus = fileLog;
config.tempDiffValue = tempDiff;
Serial.print("Saving new config :");
Serial.print(" fileLog = ");
Serial.print(config.fileLogStatus);
Serial.print(" tempDiff = ");
Serial.println(config.tempDiffValue);

saveConfiguration(filename, config);      // Save the settings to the config file
}

void sendLogFile(){
  handleFileRead("/ClocheLog.csv");
}

void getDHTData(){
//  delay(2000);
  humidity = dht.getHumidity();
  temperature = dht.getTemperature();
}

// Loads the configuration from a file
void loadConfiguration(const char *filename, Config &config) {
  // Open file for reading
  File file = SPIFFS.open(filename, "r");

  // Allocate the document on the stack.
  // Don't forget to change the capacity to match your requirements.
  // Use arduinojson.org/assistant to compute the capacity.
  StaticJsonDocument<80> doc;

  // Deserialize the JSON document
  DeserializationError error = deserializeJson(doc, file);
  if (error)
    Serial.println(F("Failed to read file, using default configuration"));

  // Get the root object in the document
  JsonObject root = doc.as<JsonObject>();

  // Copy values from the JsonObject to the Config
  config.fileLogStatus = root["fileLog"] | false;
  config.tempDiffValue = root["tempDiff"] | 5;

  // Close the file (File's destructor doesn't close the file)
  file.close();
}

// Saves the configuration to a file
void saveConfiguration(const char *filename, const Config &config) {
  // Delete existing file, otherwise the configuration is appended to the file
  SPIFFS.remove(filename);

  // Open file for writing
  File file = SPIFFS.open(filename, "w");
  if (!file) {
    Serial.println(F("Failed to create file"));
    return;
  }

  // Allocate the document on the stack.
  // Don't forget to change the capacity to match your requirements.
  // Use arduinojson.org/assistant to compute the capacity.
  StaticJsonDocument<80> doc;

  // Make our document contain an object
  JsonObject root = doc.to<JsonObject>();

  // Set the values in the object
  root["fileLog"] = config.fileLogStatus;
  root["tempDiff"] = config.tempDiffValue;

  // Serialize JSON to file
  if (serializeJson(doc, file) == 0) {
    Serial.println(F("Failed to write to file"));
  }

  // Close the file (File's destructor doesn't close the file)
  file.close();
}

void setup() {
  Serial.begin(115200);
  while (!Serial) continue;
  Serial.println("Cloche Temperature Mamagement System");
  pinMode(FAN, OUTPUT);
  pinMode(HEATER, OUTPUT);
  analogWriteFreq(10000);

  ESP.wdtDisable();   //dissable the watchdog as we dont need it

  dht.setup(DHT_PIN, DHTesp::DHT11); // Connect DHT sensor to GPIO 17

  Serial.println();
  Serial.println("Configuring access point...");

  // Initialize SPIFFS library
  while (!SPIFFS.begin()) {
    Serial.println(F("Failed to initialize SD library"));
    delay(1000);
  }

  Serial.println("SPIFFS opened:");

// Should load default config if run for the first time
  Serial.println(F("Loading configuration..."));
  loadConfiguration(filename, config);
  fileLog = config.fileLogStatus;
  tempDiff = config.tempDiffValue;
  if(config.fileLogStatus){
    prnLog.attach(10, printToLog);
  }
  //set-up the custom IP address
//  WiFi.mode(WIFI_AP_STA);
//  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));   // subnet FF FF FF 00  

  /* You can remove the password parameter if you want the AP to be open. */
//  WiFi.softAP(ssid, password);

//  IPAddress myIP = WiFi.softAPIP();
WiFi.begin(apid, appass);
while (WiFi.status() != WL_CONNECTED) {    //Wait for connection
  delay(500);  
}

//  Serial.print("AP IP address: ");
//  Serial.println(myIP);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());  //Print the local IP
Serial.print("Gateway IP: ");
Serial.println(WiFi.gatewayIP()); //Print the Gareway IP address

//httpUpdater.setup(&server);

  server.on("/", handleRoot );
  server.on("/updateData",sendTempUpdate);
  server.on("/updatefw",prepUpdate);
  server.on("/setDiff", handleDiffChange);
  server.on("/setTime", setLocalTime);
  server.on("/log", logData);
  server.on("/getlog", handleDownload);
  server.on("/ClocheLog.csv", handleDownload);
  server.on ( "/inline", []() {
    server.send ( 200, "text/plain", "this works as well" );
  } );

  server.onNotFound ( handleNotFound );
  server.begin();
  Serial.println("HTTP server started");

  sensors.begin();  //start monitoring the sensors
  PIDa.SetMode(AUTOMATIC); //start up the PID heating system
  PIDa.SetOutputLimits(0, 1024);

  delay(15);

  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  //Check the temperature sensors
  if (!sensors.getAddress(Sensor0, 0)) Serial.println("Unable to find address for Device 0");
  if (!sensors.getAddress(Sensor1, 1)) Serial.println("Unable to find address for Device 1");
  if (!sensors.getAddress(Sensor2, 2)) Serial.println("Unable to find address for Device 2");

  // set the resolution to 12 bit per device
  sensors.setResolution(Sensor0, TEMPERATURE_PRECISION);
  sensors.setResolution(Sensor1, TEMPERATURE_PRECISION);
  sensors.setResolution(Sensor2, TEMPERATURE_PRECISION);

  sensors.requestTemperatures();
  Sensor[0] = sensors.getTempC(Sensor0);
  Sensor[1] = sensors.getTempC(Sensor1);
  Sensor[2] = sensors.getTempC(Sensor2);

  Serial.println("Staring Temperature Monitor");
  udtemp.attach(2, updateTemperature); //update the temperature's every 2 seconds

  Serial.println("Starting PID Heating Controll");
  doPID.attach(5, calculatePID); // Calculate and Update the PID.

  Serial.println("Starting Humiditiy Sensor");
  DHTSensor.attach(2, dhtTicker);
}

void loop() {
  server.handleClient();
  if (getDHT) {
    getDHTData();
    getDHT = false;
  }
}

void startSPIFFS() { // Start the SPIFFS and list all contents
  SPIFFS.begin();                             // Start the SPI Flash File System (SPIFFS)
  Serial.println("SPIFFS started. Contents:");
  {
    Dir dir = SPIFFS.openDir("/");
    while (dir.next()) {                      // List the file system contents
      String fileName = dir.fileName();
      size_t fileSize = dir.fileSize();
      Serial.printf("\tFS File: %s, size: %s\r\n", fileName.c_str(), formatBytes(fileSize).c_str());
    }
    Serial.printf("\n");
  }
}

String formatBytes(size_t bytes) { // convert sizes in bytes to KB and MB
  if (bytes < 1024) {
    return String(bytes) + "B";
  } else if (bytes < (1024 * 1024)) {
    return String(bytes / 1024.0) + "KB";
  } else if (bytes < (1024 * 1024 * 1024)) {
    return String(bytes / 1024.0 / 1024.0) + "MB";
  }
}

bool handleFileRead(String path) { // send the right file to the client (if it exists)
  Serial.println("handleFileRead: " + path);
//  if (path.endsWith("/")) path += "index.html";          // If a folder is requested, send the index file
//  String contentType = getContentType(path);             // Get the MIME type
//  String pathWithGz = path + ".gz";
  if (SPIFFS.exists(path)) { // If the file exists, either as a compressed archive, or normal
    File file = SPIFFS.open(path, "r");                    // Open the file
    size_t sent = server.streamFile(file, "application/octet-stream");    // Send it to the client
    file.close();                                          // Close the file again
    Serial.println(String("\tSent file: ") + path);
    return true;
  }
  Serial.println(String("\tFile Not Found: ") + path);   // If the file doesn't exist, return false
  return false;
}

void handleDownload(){
  if (!SPIFFS.begin()) {
    Serial.println("SPIFFS failed to mount !\r\n");                    
  }
  else {
    String str = "";
    File f = SPIFFS.open("/ClocheLog.csv", "r");
    if (!f) {
      Serial.println("Can't open SPIFFS file !\r\n");          
    }
    else {
      char buf[1024];
      int siz = f.size();
      while(siz > 0) {
        size_t len = std::min((int)(sizeof(buf) - 1), siz);
        f.read((uint8_t *)buf, len);
        buf[len] = 0;
        str += buf;
        siz -= sizeof(buf) - 1;
      }
      f.close();
      Serial.println("Sending Log File");
      server.send(200, "text/plain", str);
    }
  }
}

const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html lang="en" >
<head>
  <title>Antartic Cloche Heater V1.01b</title>
<style>
body {
  background-color: #37474f;
  font-family: source-sans-pro, sans-serif;
  font-size: 16px;
}
.scale{
  display:flex;
  width: 100%;
  justify-content: space-between;
  color:white;
}
.outerWrap {
  overflow:hidden;
  display: flex;
  justify-content: center;
  flex-direction:column;
  margin-top: 1em;
}
.fixOff{
  position:relative;
  left:20px;
}
.inwrap{
  display:flex;
  flex-direction: column;
  justify-content:center;
}
.offsetLabel{
  align-self:center;
  font-size: 1.4em !important;
}
.adjustOffset{
  align-self:center;
  //background-color: #aeb4bf;
  padding: 2em;
  margin-top: 1em;
  display:flex;
  flex-direction: column;
  justify-content: space-around;
  min-height: 80px;
}
.title {
  letter-spacing: -0.025em;
}
#intext{
  padding-top: 20px;
}
:root {
  --therm-left: 5%;
  --therm-top: 5px;
  --therm-width: 300px;
  --therm-height: 300px;
}

.thermometer {
  align-self: center;
  font-family: sans-serif;
  color: #333;
  min-width: 300px;
  min-height: 300px;
  height: 70vh;
  width: 70vh;
  max-width:75vw;
  max-height:75vw;
  margin: 0px 0px;
  border-radius: 50%;
  background-color: #ededed;
  box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.4);
}

.ring {
  position: relative;
  left: 2%;
  top: 2%;
  width: 96%;
  height: 96%;
  margin: 0px, 0px;
  border-radius: 50%;
  background-color: rgba(255, 170, 0, 1);
  background: linear-gradient(
    to right,
    rgba(66, 165, 245, 1) 0%,
    rgba(244, 255, 84, 1) 35%,
    rgba(255, 153, 43, 1) 75%,
    rgba(255, 38, 38, 1) 100%
  );
  box-shadow: inset 2px 4px 4px 0px rgba(0, 0, 0, 0.3);

  .dial-bottom {
    position: relative;
    top: 62%;
    left: 25%;
    width: 50%;
    height: 50%;
    background-color: #ededed;
    border-radius: 0 0 0 95%;
    transform: rotate(-45deg);
  }
}

.temperatureContainer {
  position: relative;
  top: -79%;
  left: 17%;
  width: 65%;
  height: 65%;
  background-color: #fff;
  border-radius: 50%;
  box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.25);
  //  padding: 0em;
  //  text-align: center;
}

.pointer {
  position: absolute;
  top: -25%;
  left: 48.6%;
  width: 3%;
  height: 21%;
  border-radius: 50%;
  background-color: #fff;
  border: solid 2px #fff;
  transform-origin: 25% 290%;
  box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.25);
}
.pointer.inside {
  background-color: #ffaa00;
  transform-origin: 25% 330%;
}
.pointer.outside {
  background-color: #ff3c00;
  transform: rotate(30deg);
}
.pointer.ground{
  background-color: #56c120;
  transform-origin: 25% 330%;
}
.title {
 display:flex;
  justify-content:center;
  font-size: 6.5vh;
  text-align: center;
  text-shadow: 1px 2px 4px #212121;

}

.temperature {
  position: relative;
  top: calc(var(--therm-width) / 20);
  left: 0%;

  font-size: 6vh;
  margin-top: -0.6em;
  text-align: center;
  text-shadow: 1px 2px 4px #212121;
   margin-bottom: 0.3em;
}
.inside {
  color: #ffaa00;
}
.outside {
  color: #ff3c00;
}
.ground{
  color: #56c120;
}
.offsetLabel {

  color: #fbe9e7;
  font-size: calc(var(--therm-width) / 20);
  //text-align: center;
  text-shadow: 1px 2px 4px #212121;
}

.offsetTemp {
  align-self:center;
  color: #dd2c00;
  font-size: font-size: 1.4em !important;
  //text-align: center;
  //  text-shadow: 1px 1px 1px #FBE9E7;
}

.degree {
  font-size: 0.6em;
  position: absolute;
  margin-top: 0.2em;
}

.offsetTemperature {
  align-self:center;
 // background-color: #ff3c00;
  width:300px;
}

[type="range"] {
  -webkit-appearance: none;
  margin: 0px 0px;
  width: var(--therm-width);
  height: 3%;
  position: relative;

}

[type="range"]:focus {
  outline: 0;
}

[type="range"]:focus::-webkit-slider-runnable-track {
  background: #fbfbfc;
}

[type="range"]:focus::-ms-fill-lower {
  background: #eceff1;
}

[type="range"]:focus::-ms-fill-upper {
  background: #fbfbfc;
}

[type="range"]::-webkit-slider-runnable-track {
  cursor: pointer;
  height: 8px;
  transition: all 0.2s ease;
  width: 100%;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2), 0 0 1px rgba(13, 13, 13, 0.2);
  background: #eceff1;
  border: 4px solid #cfd8dc;
  border-radius: 5px;
}

[type="range"]::-webkit-slider-thumb {
  box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.2), 0 0 4px rgba(13, 13, 13, 0.2);
  background: #607d8b;
  border: 2px solid #eceff1;
  border-radius: 12px;
  cursor: pointer;
  height: 24px;
  width: 24px;
  -webkit-appearance: none;
  margin-top: -10px;
}

[type="range"]::-moz-range-track {
  cursor: pointer;
  height: 8px;
  transition: all 0.2s ease;
  width: 100%;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2), 0 0 1px rgba(13, 13, 13, 0.2);
  background: #eceff1;
  border: 2px solid #cfd8dc;
  border-radius: 5px;
}

[type="range"]::-moz-range-thumb {
  box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.2), 0 0 4px rgba(13, 13, 13, 0.2);
  background: #607d8b;
  border: 2px solid #eceff1;
  border-radius: 12px;
  cursor: pointer;
  height: 24px;
  width: 24px;
}

[type="range"]::-ms-track {
  cursor: pointer;
  height: 8px;
  transition: all 0.2s ease;
  width: 100%;
  background: transparent;
  border-color: transparent;
  border-width: 12px 0;
  color: transparent;
}

[type="range"]::-ms-fill-lower {
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2), 0 0 1px rgba(13, 13, 13, 0.2);
  background: #dde3e6;
  border: 2px solid #cfd8dc;
  border-radius: 10px;
}

[type="range"]::-ms-fill-upper {
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2), 0 0 1px rgba(13, 13, 13, 0.2);
  background: #eceff1;
  border: 2px solid #cfd8dc;
  border-radius: 10px;
}

[type="range"]::-ms-thumb {
  box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.2), 0 0 4px rgba(13, 13, 13, 0.2);
  background: #607d8b;
  border: 2px solid #eceff1;
  border-radius: 12px;
  cursor: pointer;
  height: 24px;
  width: 24px;
  margin-top: 0;
}

.topcoat-range-input--vertical {
  -webkit-transform: rotate(-90deg);
  -moz-transform: rotate(-90deg);
  -ms-transform: rotate(-90deg);
  transform: rotate(-90deg);
}
@media only screen and (max-width: 600px) {
  .title, .temperature{
    font-size: 6.2vw;
  }
}

.time{
    font-family: sans-serif;
    color: white;
}
.date{
    font-family: sans-serif;
    color: white;
}
</style>
<script>
  window.console = window.console || function(t) {};
</script>

  <script>
  if (document.location.search.match(/type=embed/gi)) {
    window.parent.postMessage("resize", "*");
  }
</script>

</head>

<body translate="no" onload="GetParamaters();">
<table align="left" width="100%" height="100%" frame="none" rules="none">
  <tr valign="top">
    <td width="20%"><div class="box">
  <div class="time">
    <span id="curTime" class="time">00:00</span>
  </div>
  <div class="date">
    <span id="curDate" class="date">01/01/1990</span>
  </div>
<!--    <div class="utime">
    <span id="curUtime" class="date">01/01/1990</span>
-->    
  </div>
</div><br>
<input type="submit" name="Set_Time" value="Set Time" onclick="sendTime()"><input id="logdata" type="submit" name="datalog" value="Datalog OFF" onclick="datalog()">
<a href="/ClocheLog.csv" download><input id="download" type="submit" name="download" value="Download Log"></a>
    </td>
    <td width="10%"><div  class="outerWrap">
  <div class="inwrap">
    <div class="thermometer">
      <div class="ring">
        <div class="dial-bottom"></div>
      </div>
      <div id="tc" class="temperatureContainer">
        <div id="groundpt" class="pointer ground" style="transform:rotate(12deg);"></div>
        <div id="insidept" class="pointer inside" style="transform:rotate(100deg);"></div>
        <div id="outsidept" class="pointer outside"></div>

        <div id="intext" class="title outside">outside</div>
        <div id="outsidetxt" class="temperature outside">
          <span id="outsideNum">50</span>&deg;<span id="degree" class="degree"></span>
        </div>
        <div class="title inside">
          inside
        </div>
        <div id="insidetxt" class="temperature inside">
          <span id="insideNum">120</span>&deg;<span id="degree1" class="degree"></span>
        </div>
        <div class="title ground">
          ground
        </div>
        <div id="groundtxt" class="temperature ground">
          <span id="groundNum">20</span>&deg;<span id="degree2" class="degree"></span>
        </div>
      </div>
    </div>
    <div class="adjustOffset">

      <div class="offsetLabel">Set Temperature Offset: <span id="offset" class="offsetTemp">5</span><span class="offsetTemp">&deg;</span></div>
      <div class='scale'>
        <p>+0&deg;</p>
        <p class="fixOff">+20&deg;</p>
      </div>

      <!-- <div class="offsetTemperature"><input type="range" id="tmpoff" min="0" max="20" value="5" step="1" onmouseclick="test()"; onmouseup="sendDiff()"; onChange="test()";></div>-->
      <div class="offsetTemperature"><input type="range" id="tmpoff" min="0" max="20" value="5" step="1";></div>
    </div>
  </div>
</div></td>
    <td><div id="gauge"/></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</table>
    <script >

  //Create all the variables for the page elements

  var v1 = document.getElementById('logdata');    //Log Button
  var v2 = document.getElementById('tmpoff');     // Temperature Differential Slider
  var v3 = document.getElementById('offset');     // Temperature Differnetial Text

  var v4 = document.getElementById('outsidetxt'); // v2 Outside temperature display inside the gauge
  var v5 = document.getElementById('groundtxt');  // v6 Ground Temperature display inside gauge
  var v6 = document.getElementById('insidetxt');  // v1 Inside temperature display inside the gauge

  var v7 = document.getElementById('insidept');   // v8 Inside Temperature Gauge Pointer
  var v8 = document.getElementById('groundpt');   // v7 Ground Temperature Gauge Pointer
  var v9 = document.getElementById('outsidept');  // v9 Outside Temperature Gauge Pointer

  var v10 = document.getElementById('tmpoff');     // v10 Temperature Differential Slider
  var v11 = document.getElementById('offset');     // v11 Temperature Differnetial Text

Icris={};Icris.DoubleGauge=function(n,t){var i=this;i.element=document.getElementById(n);i.element.innerHTML=Icris.GaugeMarkup;i.element.firstChild.setAttribute("height",t);i.element.firstChild.setAttribute("width",t);i.value1=0;i.value2=0;i.OEE=0;i.delta=0;i.setValues=function(n,t){if(n!==null){i.value1=n;var r=n/100*60;i.element.getElementsByClassName("needle1")[0].setAttribute("transform","rotate(-"+r+",0,100)")}t!==null&&(i.value2=t,r=t/100*60,i.element.getElementsByClassName("needle2")[0].setAttribute("transform","rotate("+r+",100,100)"));i.element.getElementsByClassName("aggregated")[0].innerHTML="OEE "+Math.round(parseFloat(i.value1)*parseFloat(i.value2)/100)+" %"};i.animationDelay=250;i.animateRandom=function(n){n!=null&&(i.animationDelay=n);var r=Math.random()>.5,t=Math.random()*10;r?i.value1+=t:i.value1-=t;(i.value1>100||i.value1<0)&&(i.value1=50);i.setValues(i.value1,null);r=Math.random()>.5;t=Math.random()*10;r?i.value2+=t:i.value2-=t;(i.value2>100||i.value2<0)&&(i.value2=50);i.setValues(null,i.value2);setTimeout(i.animateRandom,i.animationDelay)}};Icris.GaugeMarkup='<svg viewBox="0 0 120 120"><g transform= "translate(10,10)"> <rect style="fill:#EEEEEE;stroke-width:0.3;stroke:#000000;stroke-opacity:1" id="rect3680" width="114" height="100" x="-7" y="0" /> <text x="40" y="95" style="font-family:Arial; font-size:4px" class="aggregated">OEE<\/text><path style="fill:none;stroke:#AA0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 100,100" class="needle1" inkscape:connector-curvature="0" transform="rotate(-60,0,100)" /> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-30,0,100)" /> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-6,0,100)" /> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-12,0,100)" /> <text x="100" y="101" transform="rotate(-12,0,100)" style="font-family:Arial; font-size:4px">20%<\/text> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-18,0,100)" /> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-24,0,100)" /> <text x="100" y="101" transform="rotate(-24,0,100)" style="font-family:Arial; font-size:4px">40%<\/text> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-36,0,100)" /> <text x="100" y="101" transform="rotate(-36,0,100)" style="font-family:Arial; font-size:4px">60%<\/text> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-42,0,100)" /> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-48,0,100)" /> <text x="100" y="101" transform="rotate(-48,0,100)" style="font-family:Arial; font-size:4px">80%<\/text> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-54,0,100)" /> <path style="fill:none;stroke:#AA0000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 95,100 100,100" inkscape:connector-curvature="0" transform="rotate(-60,0,100)" /> <text x="100" y="100" transform="rotate(-58,0,100)" style="font-family:Arial; font-size:4px">100%<\/text> <path style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 100,100 0,100" class="needle2" inkscape:connector-curvature="0" transform="rotate(60,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(30,100,100)" /> <text x="-8" y="101" transform="rotate(36,100,100)" style="font-family:Arial; font-size:4px">60%<\/text> <text x="-8" y="101" transform="rotate(12,100,100)" style="font-family:Arial; font-size:4px">20%<\/text> <text x="-8" y="101" transform="rotate(24,100,100)" style="font-family:Arial; font-size:4px">40%<\/text> <text x="-8" y="101" transform="rotate(48,100,100)" style="font-family:Arial; font-size:4px">80%<\/text> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(60,100,100)" /> <text x="-10" y="100" transform="rotate(58,100,100)" style="font-family:Arial; font-size:4px">100%<\/text> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(6,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(12,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(18,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(24,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(36,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(42,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(48,100,100)" /> <path style="fill:none;stroke:#000000;stroke-width:0.4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 0,100 5,100" inkscape:connector-curvature="0" transform="rotate(54,100,100)" /> <ellipse style="fill:#ff0000;stroke:#000000;stroke-width:0.1;stroke-opacity:1" id="path4493" cx="0" cy="100" rx="1.3" ry="1.3" /> <ellipse style="fill:#000000;stroke:#000000;stroke-width:0.1;stroke-opacity:1" id="path4495" cx="100" cy="100" rx="1.3" ry="1.3" /> <\/g > <\/svg >';

// v10 : var slider = document.getElementById("myRange");
// V11 var output = document.getElementById("demo");
//output.innerHTML = slider.value;

v10.oninput = function() {
  v11.innerHTML = this.value;
}

v10.onmouseup = function(){
  sendDiff();
}

function GetParamaters(){

      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
          if(xhttp.readyState == 4) {
              var r = xhttp.responseText.split("|");
          //}
          if(r[0] == "1"){
                //turn the log on and change the button label
                v1.value = "Datalog ON";
          }
          if(r[0] == "0"){
                //turn the datalog off
                v1.value = "Datalog OFF";
          }
           //var diff = document.getElementById('tmpoff'); v10
           //let dispNum = document.getElementById('offset'); v11
            v10.value = parseInt(r[1]);            //Update Slider with Value
            v11.innerHTML = parseInt(r[1]);                  //Update Text with Value
          }
    }; 
    xhttp.open("GET", "log?LogStatus=true", true);    
    xhttp.send();  
}

        var gauge=new Icris.DoubleGauge('gauge',300);
//        gauge.setValues(0, 10);
//        gauge.animateRandom(250);

function downloadlog(){
    var xhttp = new XMLHttpRequest();
    xhttp.open("GET", "getlog?file=/ClocheLog.csv", true);
    xhttp.send();
}

function datalog(){
//Best we update the time just to be sure its set.
  var date = new Date();
  var uTime = date.getTime();
  var hrs = date.getHours();
  var mins = date.getMinutes();
  var secs = date.getSeconds();
  var days = date.getDate();
  var months = date.getMonth();
  var years = date.getFullYear();

  var bt1 = document.getElementById('logdata');
  var st;
  var xhttp = new XMLHttpRequest();

  if(bt1.value == "Datalog OFF"){
    //turn the log on and change the button label
    bt1.value = "Datalog ON";
    st = "ON";
  }else{
    //turn the datalog off
    bt1.value = "Datalog OFF";
    st = "OFF";
  }
    xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
    }
  };
  //xhttp.open("GET", "setTime?hr="+hrs+"&min=" +mins+"&sec="+secs+"&day="+days+"&month="+months+"&year="+years, true);
//  xhttp.open("GET", "log?logcmd="+st, true);
  xhttp.open("GET", "log?logcmd="+st+"&hr="+hrs+"&min=" +mins+"&sec="+secs+"&day="+days+"&month="+months+"&year="+years, true);
  xhttp.send();
}

//Update the time every second
function showTime(){
  var t1 = document.getElementById('curTime');  // Time Location
//  var t3 = document.getElementById('curUtime');
  var date = new Date();
  var nowTime = date.toLocaleTimeString();
  t1.innerHTML = nowTime;
//  t3.innerHTML = date.getTime();
}
showTime();
setInterval(showTime, 1000); //2000mSeconds update rate

//Update the date every hour, no point in writing it every second
function showDate() {
  var t2 = document.getElementById('curDate'); //  Date Location
  var date = new Date();
  var todayDate = date.toDateString();
  t2.innerHTML = todayDate;
};
showDate();
setInterval(showDate, 3600000); // update date every hour

//const inputs = [].slice.call(document.querySelectorAll('input'));
var p1 = createRemap(-40,120, -130,130);  //Temperature Mapping
var p2 = createRemap(-40,120, -130,130);  //Temperature Mapping
var p3 = createRemap(800,442, 0, 100);  //Moisture Mapping
var p4 = createRemap(0,100, 0, 100);   //Humidity Mapping
var process = 1;

//inputs.forEach(input => input.addEventListener('change', handleUpdate));
//inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));
//inputs.forEach(input => input.addEventListener('change', sendDiff));
//inputs.forEach(input => input.addEventListener('mousemove', test));

function haltUpdates(){
  process = 0;
}

function createRemap(inMin, inMax, outMin, outMax) {
    return function remaper(x) {
        return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
    };
};

//function handleUpdate(e) {
//  document.getElementById("outsidetxt").innerHTML = document.getElementById("inside").value+"&deg;";
//  document.getElementById("outsidept").style.transform = "rotate("+p2(document.getElementById("outside").value)+"deg)";
//  document.getElementById("insidetxt").innerHTML = document.getElementById("outside").value+"&deg;";
//  document.getElementById("insidept").style.transform = "rotate("+p1(document.getElementById("inside").value)+"deg)";
//};

function getUpdate(){
      // 'xmlhttp' variable will hold the XMLHttpRequest object
      var xmlhttp = false;
      xmlhttp = new XMLHttpRequest();
      xmlhttp.overrideMimeType('text/xml');

//    var url = "updateData";    
//    xmlhttp.open("GET", url, true);

    xmlhttp.onreadystatechange = function() {
      if(xmlhttp.readyState == 4) {
    //v4 = outsidetxt, v5 = groundtxt, v6 = insidetxt, v7 = insidept, v8 = groundpt, v9 = outsidept
    //r[0] outside, r[1] ground,  r[2] inside, r[3] tempDiff, r[4] setDiff, r[5] soilmoisture, r[6] humidity

        var r = xmlhttp.responseText.split("|");

        v4.innerHTML = r[0]+"&deg;";                //Outside Temperature
        v5.innerHTML = r[1]+"&deg;";                //Ground Temperature
        v6.innerHTML = r[2]+"&deg;";                //Inside Temperature

        v9.style.transform = "rotate("+p2(r[0])+"deg)";
        v8.style.transform = "rotate("+p2(r[1])+"deg)";
        v7.style.transform = "rotate("+p2(r[2])+"deg)";

        gauge.setValues(p3(r[5]), p4(r[6]));
      }
    };
    var url = "updateData";    
    xmlhttp.open("GET", url, true);    
    xmlhttp.send();  
}

setInterval(function() {
    // Call a function repetatively with 3 Second interval
    getUpdate();
}, 3000); //3000mSeconds update rate

function sendDiff() {
  var xhttp = new XMLHttpRequest();
  var diff = document.getElementById('tmpoff'); // slider
  let dispNum = document.getElementById('offset'); // text for displaying the offset temperature
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        dispNum.innerHTML = diff.value;
        process = 1; // start monitoring again
    }
  };
  xhttp.open("GET", "setDiff?diff="+diff.value, true);
  xhttp.send();
}

function sendTime() {

//getFullYear()  Get the year as a four digit number (yyyy)
//getMonth()  Get the month as a number (0-11)
//getDate() Get the day as a number (1-31)
//getHours()  Get the hour (0-23)
//getMinutes()  Get the minute (0-59)
//getSeconds()  Get the second (0-59)
//getMilliseconds() Get the millisecond (0-999)
//getTime() Get the time (milliseconds since January 1, 1970)
//getDay()  Get the weekday as a number (0-6)

  var xhttp = new XMLHttpRequest();
  var date = new Date();
  var uTime = date.getTime();
  var hrs = date.getHours();
  var mins = date.getMinutes();
  var secs = date.getSeconds();
  var days = date.getDate();
  var months = date.getMonth();
  var years = date.getFullYear();
  //setTime(hr,min,sec,day,month,yr); // pass the data to arduino
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
    }
  };
  //var date = new Date();
  xhttp.open("GET", "setTime?hr="+hrs+"&min=" +mins+"&sec="+secs+"&day="+days+"&month="+months+"&year="+years, true);
  xhttp.send();
}

function test () {
 var diff = document.getElementById('tmpoff');
 let dispNum = document.getElementById('offset');
  //console.log(dispNum.value);
  dispNum.innerHTML = diff.value;
  //console.log(diff.value);
  function textUpdate(n) {

  }

}

    </script>  

<script language="javascript" type="text/JavaScript">

        function getLog(log, lines) {
                var url = "getLogFile.php?log=" + log + "&lines=" + lines;
                request.open("GET", url, true);
                request.onreadystatechange = updatePage;
                request.send(null);
        }

        function tail(command,log,lines) {
                if (command == "start") {
                        document.getElementById("watchStart").disabled = true;
                        document.getElementById("watchStop").disabled = false;
                        timer = setInterval(function() {getLog(log,lines);},5000);
                } else {
                        document.getElementById("watchStart").disabled = false;
                        document.getElementById("watchStop").disabled = true;
                        clearTimeout(timer);
                }
        }

        function updatePage() {
                if (request.readyState == 4) {
                        if (request.status == 200) {
                                var currentLogValue = request.responseText.split("\n");
                                eval(currentLogValue);

                                document.getElementById("log").innerHTML = currentLogValue;
                        }
                }
        }

        var request = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ActiveXObject ? new window.ActiveXObject("Microsoft.XMLHTTP") : false);
</script>

</body>

</html>
)=====";

Debug Messages

Debug messages go here
Pablo2048 commented 6 years ago

Are You sure that You get the letter "M" in MCVE (Minimal) right? :-) this does not look like MCVE to me. I don't want to waste my time studying this poorly formatted and hard-to-read code, but as I remember I faced similar problem with weak wifi - try to check wifi status before any outgoing communication - especially when creating new connection.

vangalvin commented 6 years ago

@Pablo2048 This is the complete code, I tried to format it but had no luck doing so.

The issue defiantly seems to be a result of having poor wireless signal, for testing purposes I have set up a wireless repeater in the workshop and the issue has now vanished however this project is destined to end up in a rather remote location as a stand alone device where there may not be any internet connectivity.

What I was thinking is doing a check on the RSSI and either denying access to the user or if its in client mode stopping the unit from connecting to an AP if the signal is below the threshold.

I thought I would share this issue mainly because the problem was not obvious and quite random resulting in me chasing ghosts when the problem was a lot less complex than I had thought. And it appears that a few others may have been having the same issue and blaming it on the power supply or other things rather than what has ended up being an RSSI signal issue.

Pablo2048 commented 6 years ago

Can you please try to monitor (and log somewhere) WiFi.status(), RSSI and decode exception dump?

vangalvin commented 6 years ago

@Pablo2048 I turn off the repeater I have set up and log the RSSI. I don't seem to be getting an exception dump any more, Initially I did get one but was not able to decide it with the exception decoder not returning anything.

What I did see was that as soon as the signal level dropped to below -87 to -91 this is when the WDT would randomly trigger often resulting in either cyclic restarts or the system just stopping.

Pablo2048 commented 6 years ago

Cyclic restarts? Can You check power source (and whole power path to the ESP), try another power supply, add some capacitors, ...

vangalvin commented 6 years ago

@Pablo2048 I replaced the PSU, built another one and checked the ripple. Defiantly not that. With another AP set up as a repeater in my workshop and a signal level of -42 there have been no more wdt reset's

When I say cyclic restarts, the system will trigger a wdt reset, restart and run for what seems to be anything from 5 minutes to half an hour then do another wdt reset and restart again.

Pablo2048 commented 6 years ago

Ok, so without stack trace decoding and wifi.status monitoring I have no idea what else to do...

vangalvin commented 6 years ago

@Pablo2048 working on that now, as these things always go its not throwing the error as quickly as it was earlier.

vangalvin commented 6 years ago

Reset Reason: External System WiFi Status: 3 RSSI: -92 Reset Reason: External System WiFi Status: 3 RSSI: -92 Reset Reason: External System WiFi Status: 3 RSSI: -92 Reset Reason: External System WiFi Status: 3 RSSI: -92 Reset Reason: External System WiFi Status: 3 RSSI: -93

ets Jan 8 2013,rst cause:4, boot mode:(1,7)

wdt reset

vangalvin commented 6 years ago

@Pablo2048 Looks like as soon as the signal drops to about -93 that is when the wdt reset is triggered.

Pablo2048 commented 6 years ago

IMHO boot mode (1,7) is not the good one.

vangalvin commented 6 years ago

@Pablo2048 Finally i got a stack dump Sadly I can not decode it as the decoder will not run on my system for some reason.

eset Reason: External System WiFi Status: 3 RSSI: -91

Soft WDT reset

ctx: sys sp: 3fffecf0 end: 3fffffb0 offset: 01b0

stack>>> 3fffeea0: 00000000 000007c6 00000000 3fffee34
3fffeeb0: 00000000 3fffdcb0 3ffeedd8 00000030
3fffeec0: 3fffeee0 3fffeee0 00000004 40237b56
3fffeed0: 00000000 00000008 00000018 00000000
3fffeee0: 3ffe9650 3ffe966c 000007c6 00000001
3fffeef0: 00000018 0000000c 00000000 60000600
3fffef00: c50b9bbe 3ffef940 3ffeed88 4021bec5
3fffef10: 00000000 3ffede48 00000000 00000000
3fffef20: 40237968 3ffede48 3ffeedb0 60000600
3fffef30: 4023a5b9 3ffede48 3ffeedb0 c50b9bbe
3fffef40: 4023a5fe 3fffdab0 00000000 3fffdcb0
3fffef50: 3ffeedd8 3fffdad0 3ffef788 402124e7
3fffef60: 40000f49 40000f49 3fffdab0 40000f49
3fffef70: 40000e19 40001878 00000002 00000000
3fffef80: 3fffff10 aa55aa55 000000ee 40104424
3fffef90: 4010442a 00000002 00000000 0e31c8f7
3fffefa0: 4010000d 8ae2a40f c577916c 8249d4fc
3fffefb0: 00000000 3fffef4c 00000000 3fffff18
3fffefc0: 3fffffd0 00000000 00000000 feefeffe
3fffefd0: feefeffe feefeffe feefeffe feefeffe
3fffefe0: feefeffe feefeffe feefeffe feefeffe
3fffeff0: feefeffe feefeffe feefeffe feefeffe
3ffff000: feefeffe feefeffe feefeffe feefeffe
3ffff010: feefeffe feefeffe feefeffe feefeffe
3ffff020: feefeffe feefeffe feefeffe feefeffe
3ffff030: feefeffe feefeffe feefeffe feefeffe
3ffff040: feefeffe feefeffe feefeffe feefeffe
3ffff050: feefeffe feefeffe feefeffe feefeffe
3ffff060: feefeffe feefeffe feefeffe feefeffe
3ffff070: feefeffe feefeffe feefeffe feefeffe
3ffff080: feefeffe feefeffe feefeffe feefeffe
3ffff090: feefeffe feefeffe feefeffe feefeffe
3ffff0a0: feefeffe feefeffe feefeffe feefeffe
3ffff0b0: feefeffe feefeffe feefeffe feefeffe
3ffff0c0: feefeffe feefeffe feefeffe feefeffe
3ffff0d0: feefeffe feefeffe feefeffe feefeffe
3ffff0e0: feefeffe feefeffe feefeffe feefeffe
3ffff0f0: feefeffe feefeffe feefeffe feefeffe
3ffff100: feefeffe feefeffe feefeffe feefeffe
3ffff110: feefeffe feefeffe feefeffe feefeffe
3ffff120: feefeffe feefeffe feefeffe feefeffe
3ffff130: feefeffe feefeffe feefeffe feefeffe
3ffff140: feefeffe feefeffe feefeffe feefeffe
3ffff150: feefeffe feefeffe feefeffe feefeffe
3ffff160: feefeffe feefeffe feefeffe feefeffe
3ffff170: feefeffe feefeffe feefeffe feefeffe
3ffff180: feefeffe feefeffe feefeffe feefeffe
3ffff190: feefeffe feefeffe feefeffe feefeffe
3ffff1a0: feefeffe feefeffe feefeffe feefeffe
3ffff1b0: feefeffe feefeffe feefeffe feefeffe
3ffff1c0: feefeffe feefeffe feefeffe feefeffe
3ffff1d0: feefeffe feefeffe feefeffe feefeffe
3ffff1e0: feefeffe feefeffe feefeffe feefeffe
3ffff1f0: feefeffe feefeffe feefeffe feefeffe
3ffff200: feefeffe feefeffe feefeffe feefeffe
3ffff210: feefeffe feefeffe feefeffe feefeffe
3ffff220: feefeffe feefeffe feefeffe feefeffe
3ffff230: feefeffe feefeffe feefeffe feefeffe
3ffff240: feefeffe feefeffe feefeffe feefeffe
3ffff250: feefeffe feefeffe feefeffe feefeffe
3ffff260: feefeffe feefeffe feefeffe feefeffe
3ffff270: feefeffe feefeffe feefeffe feefeffe
3ffff280: feefeffe feefeffe feefeffe feefeffe
3ffff290: feefeffe feefeffe feefeffe feefeffe
3ffff2a0: feefeffe feefeffe feefeffe feefeffe
3ffff2b0: feefeffe feefeffe feefeffe feefeffe
3ffff2c0: feefeffe feefeffe feefeffe feefeffe
3ffff2d0: feefeffe feefeffe feefeffe feefeffe
3ffff2e0: feefeffe feefeffe feefeffe feefeffe
3ffff2f0: feefeffe feefeffe feefeffe feefeffe
3ffff300: feefeffe feefeffe feefeffe feefeffe
3ffff310: feefeffe feefeffe feefeffe feefeffe
3ffff320: feefeffe feefeffe feefeffe feefeffe
3ffff330: feefeffe feefeffe feefeffe feefeffe
3ffff340: feefeffe feefeffe feefeffe feefeffe
3ffff350: feefeffe feefeffe feefeffe feefeffe
3ffff360: feefeffe feefeffe feefeffe feefeffe
3ffff370: feefeffe feefeffe feefeffe feefeffe
3ffff380: feefeffe feefeffe feefeffe feefeffe
3ffff390: feefeffe feefeffe feefeffe feefeffe
3ffff3a0: feefeffe feefeffe feefeffe feefeffe
3ffff3b0: feefeffe feefeffe feefeffe feefeffe
3ffff3c0: feefeffe feefeffe feefeffe feefeffe
3ffff3d0: feefeffe feefeffe feefeffe feefeffe
3ffff3e0: feefeffe feefeffe feefeffe feefeffe
3ffff3f0: feefeffe feefeffe feefeffe feefeffe
3ffff400: feefeffe feefeffe feefeffe feefeffe
3ffff410: feefeffe feefeffe feefeffe feefeffe
3ffff420: feefeffe feefeffe feefeffe feefeffe
3ffff430: feefeffe feefeffe feefeffe feefeffe
3ffff440: feefeffe feefeffe feefeffe feefeffe
3ffff450: feefeffe feefeffe feefeffe feefeffe
3ffff460: feefeffe feefeffe feefeffe feefeffe
3ffff470: feefeffe feefeffe feefeffe feefeffe
3ffff480: feefeffe feefeffe feefeffe feefeffe
3ffff490: feefeffe feefeffe feefeffe feefeffe
3ffff4a0: feefeffe feefeffe feefeffe feefeffe
3ffff4b0: feefeffe feefeffe feefeffe feefeffe
3ffff4c0: feefeffe feefeffe feefeffe feefeffe
3ffff4d0: feefeffe feefeffe feefeffe feefeffe
3ffff4e0: feefeffe feefeffe feefeffe feefeffe
3ffff4f0: feefeffe feefeffe feefeffe feefeffe
3ffff500: feefeffe feefeffe feefeffe feefeffe
3ffff510: feefeffe feefeffe feefeffe feefeffe
3ffff520: feefeffe feefeffe feefeffe feefeffe
3ffff530: feefeffe feefeffe feefeffe feefeffe
3ffff540: feefeffe feefeffe feefeffe feefeffe
3ffff550: feefeffe feefeffe feefeffe feefeffe
3ffff560: feefeffe feefeffe feefeffe feefeffe
3ffff570: feefeffe feefeffe feefeffe feefeffe
3ffff580: feefeffe feefeffe feefeffe feefeffe
3ffff590: feefeffe feefeffe feefeffe feefeffe
3ffff5a0: feefeffe feefeffe feefeffe feefeffe
3ffff5b0: feefeffe feefeffe feefeffe feefeffe
3ffff5c0: feefeffe feefeffe feefeffe feefeffe
3ffff5d0: feefeffe feefeffe feefeffe feefeffe
3ffff5e0: feefeffe feefeffe feefeffe feefeffe
3ffff5f0: feefeffe feefeffe feefeffe feefeffe
3ffff600: feefeffe feefeffe feefeffe feefeffe
3ffff610: feefeffe feefeffe feefeffe feefeffe
3ffff620: feefeffe feefeffe feefeffe feefeffe
3ffff630: feefeffe feefeffe feefeffe feefeffe
3ffff640: feefeffe feefeffe feefeffe feefeffe
3ffff650: feefeffe feefeffe feefeffe feefeffe
3ffff660: feefeffe feefeffe feefeffe feefeffe
3ffff670: feefeffe feefeffe feefeffe feefeffe
3ffff680: feefeffe feefeffe feefeffe feefeffe
3ffff690: feefeffe feefeffe feefeffe feefeffe
3ffff6a0: feefeffe feefeffe feefeffe feefeffe
3ffff6b0: feefeffe feefeffe feefeffe feefeffe
3ffff6c0: feefeffe feefeffe feefeffe feefeffe
3ffff6d0: feefeffe feefeffe feefeffe feefeffe
3ffff6e0: feefeffe feefeffe feefeffe feefeffe
3ffff6f0: feefeffe feefeffe feefeffe feefeffe
3ffff700: feefeffe feefeffe feefeffe feefeffe
3ffff710: feefeffe feefeffe feefeffe feefeffe
3ffff720: feefeffe feefeffe feefeffe feefeffe
3ffff730: feefeffe feefeffe feefeffe feefeffe
3ffff740: feefeffe feefeffe feefeffe feefeffe
3ffff750: feefeffe feefeffe feefeffe feefeffe
3ffff760: feefeffe feefeffe feefeffe feefeffe
3ffff770: feefeffe feefeffe feefeffe feefeffe
3ffff780: feefeffe feefeffe feefeffe feefeffe
3ffff790: feefeffe feefeffe feefeffe feefeffe
3ffff7a0: feefeffe feefeffe feefeffe feefeffe
3ffff7b0: feefeffe feefeffe feefeffe feefeffe
3ffff7c0: feefeffe feefeffe feefeffe feefeffe
3ffff7d0: feefeffe feefeffe feefeffe feefeffe
3ffff7e0: feefeffe feefeffe feefeffe feefeffe
3ffff7f0: feefeffe feefeffe feefeffe feefeffe
3ffff800: feefeffe feefeffe feefeffe feefeffe
3ffff810: feefeffe feefeffe feefeffe feefeffe
3ffff820: feefeffe feefeffe feefeffe feefeffe
3ffff830: feefeffe feefeffe feefeffe feefeffe
3ffff840: feefeffe feefeffe feefeffe feefeffe
3ffff850: feefeffe feefeffe feefeffe feefeffe
3ffff860: 40103269 00040000 7fffffff 00000000
3ffff870: 00000022 40103266 00040000 40100f22
3ffff880: 3ffedcb8 40102192 3fff091c feefeffe
3ffff890: 00000001 40103523 00002000 00000022
3ffff8a0: 3fffc200 40106c88 00000020 40106cd0
3ffff8b0: 3ffff8c0 feefeffe 3fffc230 4000050c
3ffff8c0: 4000bd9c 00000030 00000013 ffffffff
3ffff8d0: 40000fb0 0000023a 00000501 3fffc200
3ffff8e0: 0000073b ffffffff 00000020 00000022
3ffff8f0: 3fffc200 40106c88 00000020 40106cd0
3ffff900: 00000004 3ffff9e0 3fffc230 4000050c
3ffff910: 4000bd9c 00000030 00000013 ffffffff
3ffff920: 40000fb0 0000023a 00000501 3fffc200
3ffff930: 0000073b ffffffff 00000020 00000000
3ffff940: 0000ffff 00042035 00002035 00000000
3ffff950: 00000100 3fff0c9c 0023fc00 00000030
3ffff960: 3fff0c9c 00000200 00002035 00000022
3ffff970: 3fffc200 40106c88 00000020 40106cd0
3ffff980: 00000100 3ffff9e0 3fffc230 4000050c
3ffff990: 40103ea2 00000030 0000001f fffffffe
3ffff9a0: 00000004 00000002 00000000 00000004
3ffff9b0: 00000001 3fff1e18 00000008 00000002
3ffff9c0: 0001008c 0000ffe8 00030000 3ffedcb8
3ffff9d0: 3ffedc40 00000002 00000107 00000030
3ffff9e0: 00000100 00000000 40105798 00000100
3ffff9f0: 00000000 00000000 0000001f 000000f6
3ffffa00: 0000005c 00000000 4010426a 000000f6
3ffffa10: 0000005c 00000000 4010426a 000000f9
3ffffa20: 0000005c 00000001 4010426a 3ffedcb8
3ffffa30: 3ffedc40 00000000 4010426a 000000f6
3ffffa40: 0000005c 00000001 4010426a 3ffedcb8
3ffffa50: 3ffedc40 3ffedcb8 3ffedcb8 3ffedcb8
3ffffa60: 3ffe9af5 4010431f 3ffed580 00000022
3ffffa70: 40103e6f 3ffedcb8 00000020 40106cd0
3ffffa80: 3ffe9af5 401036fa 3ffedcb8 4000050c
3ffffa90: 40100d97 00000030 00000000 ffffffff
3ffffaa0: 40103d79 3ffedcb8 3ffed210 00000022
3ffffab0: 3fffc200 40106c88 00000020 40106cd0
3ffffac0: 3fffc200 40106c88 3fffc230 4000050c
3ffffad0: 40237d97 00000030 00000000 ffffffff
3ffffae0: 402342c7 00000000 0000003c 00000000
3ffffaf0: 00000000 3ffedd90 007fffff bfc57176
3ffffb00: 3ffed980 00ffffff 00000098 00000000
3ffffb10: ffffffff 00000000 3ffe9c41 00000030
3ffffb20: 40226834 00000030 00000000 ffffffff
3ffffb30: 40226831 3fff19d8 00000001 40000000
3ffffb40: 00000000 bfffffff 00080240 c00a4004
3ffffb50: 3ffec990 000a4000 ff000fff 3ffee728
3ffffb60: 3ffefebc 00000001 3fff19d8 00000030
3ffffb70: 3fffc200 40106c88 3fffc230 4000050c
3ffffb80: 4021dcb8 00000030 00000008 ffffffff
3ffffb90: 4021dcb8 00000023 3fffdcc0 4021a918
3ffffba0: 3fff2056 0000004d 0000009e 00000003
3ffffbb0: 00000001 fffffffd 402342d3 00000001
3ffffbc0: ffffffff 00000000 3ffe9c41 00000022
3ffffbd0: 3fffc200 40106c88 00000020 40106cd0
3ffffbe0: 4023442e 3ffed1e8 3fffc230 4000050c
3ffffbf0: 4022ca94 00000030 00000008 00000022
3ffffc00: 3fffc200 40106c88 00000020 40106cd0
3ffffc10: 3fffc200 40106c88 3fffc230 4000050c
3ffffc20: 40102d03 00000030 00000019 fffffffe
3ffffc30: 3ffed508 00000023 3ffed508 3ffed530
3ffffc40: 3ffed150 ffff4f4a 3ffed150 0000012b
3ffffc50: 3ffedfb0 00000006 00000000 00000022
3ffffc60: 3fffc200 40106c88 00000020 40106cd0
3ffffc70: 3fffc200 40106c88 3fffc230 4000050c
3ffffc80: 00000000 00000000 0000001f 40104bfd
3ffffc90: 4000050c 00000023 00000001 00000022
3ffffca0: 3fffc200 40106c88 00000020 40106cd0
3ffffcb0: 40106cd0 3ff00004 3fffc230 4000050c
3ffffcc0: 40102cd8 00000030 00000019 00000022
3ffffcd0: 3fffc200 40106c88 00000020 40106cd0
3ffffce0: 3ffed150 ffff4ef5 3fffc230 4000050c
3ffffcf0: 40101dad 00000030 00000019 fffffffe
3ffffd00: 00000005 00000000 00000020 40100f22
3ffffd10: 3ffe9af5 4010431f 3ffed558 00000050
3ffffd20: 40101c3d 3ffed558 00000016 fffffc00
3ffffd30: 0000000f c50a1492 3ffedfb0 40101e0e
3ffffd40: 3ffea388 00000000 00000000 60000768
3ffffd50: 0000000f c50a1492 4010224e 00000100
3ffffd60: 7fffffff 3ffea388 3ffea388 00000001
3ffffd70: 00000001 00000080 00000020 40100f22
3ffffd80: 00000005 c50a1492 00000000 00000022
3ffffd90: 3fffc200 40106c88 00000020 40106cd0
3ffffda0: 3fffc200 40106c88 3fffc230 4000050c
3ffffdb0: 40202129 00000030 0000001d ffffffff
3ffffdc0: 40202533 00000000 00000031 007f8000
3ffffdd0: 0000007e 6000001c ff000000 3a511300
3ffffde0: 000000cc 3fff2820 00000000 3fffff1f
3ffffdf0: 00000002 3fffff20 00000000 00000022
3ffffe00: 3fffc200 40106c88 00000020 40106cd0
3ffffe10: 3fffc200 40106c88 3fffc230 4000050c
3ffffe20: 40202129 00000030 0000001d ffffffff
3ffffe30: 40202533 00000000 0000000a 007f8000
3ffffe40: 0000007e 6000001c ff000000 00000a0d
3ffffe50: 000000cc 3fff2820 00000000 3ffe8b4d
3ffffe60: 00000002 3ffe8b4e 00000000 00000030
3ffffe70: ffffffa5 3fffdad0 3ffef788 00000030
3ffffe80: 0000004a 3fff2820 00000000 3fff2822
3ffffe90: 0000000f 3fff2823 00000000 00000030
3ffffea0: 000000cc 3fff2820 00000000 3ffef6c8
3ffffeb0: 3ffef62c 3fffdad0 3ffef788 3ffef6c8
3ffffec0: 00000039 0000000a 3ffef6c8 40210ac0
3ffffed0: 00000010 00000010 00000000 40210da5
3ffffee0: 3fffff1e 40100734 40212598 00000000
3ffffef0: 00000000 00000000 3fffff1d 40211041
3fffff00: 00000010 3fffff90 3fffff90 402118f3
3fffff10: 3fffff60 0000000f 3fffff90 3139193f
3fffff20: 3a511300 3ffef788 3fffff90 3ffef788
3fffff30: 3fffdad0 00000003 3ffef6c8 40210ac0
3fffff40: 40236319 3ffef6c8 3ffef62c 40210da5
3fffff50: 3ffe8b4c ffffffa5 3ffef6c8 40211094
3fffff60: 0000000a 00000000 3ffef6c8 40210f58
3fffff70: 3fffdad0 3ffef62c 3ffef6c8 402110d8
3fffff80: 40213f68 3ffef62c 3ffef6c8 4020850c
3fffff90: 00000000 00000000 00000000 40208491
3fffffa0: 00000000 00000000 00000001 4021254d
<<<stack<<<

ets Jan 8 2013,rst cause:2, boot mode:(1,6)

ets Jan 8 2013,rst cause:4, boot mode:(1,6)

wdt reset

Pablo2048 commented 6 years ago

Without ESPException decoder output is this dump useless. Only you on your machine can decode this dump.

Pablo2048 commented 6 years ago

One more hint - try older version of the ESPEXception decoder because of this https://github.com/me-no-dev/EspExceptionDecoder/issues/36 ...

vangalvin commented 6 years ago

I gave that a quick try and get no output from the decoder. Will try reinstall it and may drop back to an earlier version of the Arduino IDE just in case the decoder issue is in there.

devyte commented 6 years ago

MAIN_page has size of about 27KB, and you are handling it with:

void handleRoot() {
 String s = MAIN_page; //Read HTML contents
 server.send(200, "text/html", s); //Send web page
}

That means that the flash string is being loaded into a String object, which requires a chunk of contiguous mem to hold it. The ESP has about 49KB of heap available with an empty sketch, which leaves 22KB for global objects, plus their inited state, plus your globals, plus the webserver state during request handling. Your sketch uses (some) sequences of String concats, which causes mem fragmentation. I'd think that, if your sketch does find a single block of free mem to hold the 27KB, it's a really close call. I'd run this with OOM debug enabled.

But that's not what caught my eye. You are trying to serve 27KB of static data as a contiguous string. Under extreme bad Wifi signal connection or intermittent connection, transmission slows down to a crawl. What did you think would happen? My suggestion: move that huge string to a file, and serve it as a stream, which is meant to be served in pieces. Your idea of limiting connections to signal qualities that don't suck is also good. The SDK now allows to filter SSIDs by RSSI value, so in theory you could just set a low threshold, and you wouldn't even see the SSID while scanning. However, that functionality is not yet exposed in our core, so you'd have to tweak the WiFi code to make use of it. A PR would be welcome!

On a personal note, I really don't understand why so many users think it's a good idea to embed huge html/js/css strings in their sketch, and handle them as strings. My experience shows that it's much better to have the html/css/js in files served from SPIFFS, and have the dynamic data served with e.g.: tiny jsons or whatever.

Besides the above, which strictly speaking are user errors, as @Pablo2048 said, the requirement here is for a MCVE sketch, where the M means Minimal, and this is far from that, so closing for now. If you can trim your sketch down to something manageable, please update your post and I'll reopen, or you can just open a new issue, fill in the required info, and link to this one.

vangalvin commented 6 years ago

Thank you @devyte I will move the javascript and html in to a file. I was wondering if the SDK had a filter option for low RSSI,

I ran the unit last night with the WiFi Repeater set up in the workshop giving the unit an average of -49 and the unit is still running with no WDT resets.

Once I get this all tweaked up I may see about moving it all to a D1 with an external antenna connection although the housing I designed and built has the NodeMCU installed as high as possible i'm sure a little bit more gain would not hurt. The great thing is this unit is also heading to a low noise environment.

I will also take your advice and move everything over to SPIFFS I did that on my IOT Air Compressor and that thing has never had any issues and has been running for a good 9 or so months 24/7.

Thank you also to @Pablo2048 :)