Analog inputs stopped working

I've run into an issue with my Uno that I can't figure out, so hoping for some advice here.

Back in May, I installed a little project that uses a water sensor and a DHT11. The last restart was on 19 July and I last observed it working on 6 August (with other periodic checks in between). Today I noticed that the water sensor was energized constantly, when I expect 10ms on and then 10000ms off. Seems that analogRead() is crashing the Uno, based on some troubleshooting where I shifted around pins, print statements, and the analogRead() statements.

If I remove either analogRead() statement, the behavior of the remaining statement remains the same. In other words, no matter which pin I attempt to read, the crash occurs.

I've tried moving to other available analog pins. I've even removed all connections to the analog pins. No matter what, analogRead() still crashes the unit. I'm not sure what to do next. As I said, this was working without issue for a number of months. I might suspect a memory issue but a reboot should clear that up, at least temporarily.

I also stuck an analogRead() statement in the setup, and with some serial debugging I see that the unit fails to reach the line after analogRead(); it reboots and then hangs.

define sensorData A5
void setup() {
  Serial.begin(9600);
    Serial.println("Initializing...");
    analogRead(sensorData);
    Serial.println("After read");
}

The above results in:
22:28:52.295 -> Initializing...
22:28:53.984 -> Initializing...

Any ideas on what might be the issue, or the best way to identify and/or work around the cause? I am fairly new to this magnificent device and I am baffled by this sudden change in performance.

-b

In the Arduino IDE, use Ctrl T or CMD T to format your code then copy the complete sketch.

Use the </> icon from the ‘reply menu’ to attach the copied sketch.

Here you go. Please go easy on me -- it was my first Arduino (and C++) project and I used the String crutch. Program memory was not nearly as valuable as SRAM so that lead to a bunch of embarrassing code. Sharing it here makes me feel like I put my pants on before my underwear and then walked down a busy street. :slight_smile:

#include <Ethernet2.h>
#include <SPI.h>
#include <DHT.h>
#include <Timezone.h>
#include <EEPROM.h>

#define sensorData A5                 // Water sensor data pin
#define sensorPower A4                 // Water sensor power pin
#define LED_WARN 3                    // LED alarm pin
#define LED_STATUS 7                  // LED status pin
#define SPEAKER 5                     // Alarm speaker pin
#define DHTTYPE DHT11                 // Sensor type (DHT11 or DHT22)
#define DHTPIN A0                     // Temp/Humidity sensor data pin

unsigned long counter = 0;             // Used to compare against millis() to determine timing for execution
unsigned long curTime = 0;             // Current millis() value
unsigned long timeCounter = 0;         // Keeps track of hours for NTP update
unsigned long minuteCounter = 0;       // Used for tracking minutes, between NTP updates
bool sensorToggle = false;             // Used to determine if sensor values should be fetched

// Hue bulbs
//const char BRIDGE_IP[] = "1.1.1.1";  // Home
const char BRIDGE_IP[] = "2.2.2.2"; // Gail's
byte bulbIDs[12] = {};        // Light IDs to use when alarm is triggered
bool bulbToggle = true;

// Sensor values
unsigned int alarmCount = 0;          // increments every 10 seconds if water level exceeds limit
bool water = false;                   // is water detected?
byte humidity = 0;                    // air humidity reading
float temperature = 0.0;              // air temperature reading
bool alarmOverride = false;           // don't send alarm if water is detected
byte curHours = 0;                    // age of water detection hours
byte curMinutes = 0;                  // age of water detection minutes
unsigned long curSeconds = 0;         // age of water detection seconds


// NTP
byte packetBuffer[48];                // buffer to hold incoming and outgoing packets
byte ntpMonth = 0;                    // timestamp month (1-12)
byte ntpDay = 0;                      // timestamp day
int ntpYear = 0;                      // timestamp year;
byte ntpHour = 0;                     // timestamp hour
byte ntpMinute = 0;                   // timestamp minute
byte ntpSecond = 0;                   // timestamp second
byte localHour = 0;                   // always store a copy of the local hour for quiet hours alarms
String zone = "UTC";                  // Textual representation of the timezone setting
// Next 6 variables are set when an alarm has triggered
byte alarmMonth = 0;                    // timestamp month (1-12)
byte alarmDay = 0;                      // timestamp day
int alarmYear = 0;                      // timestamp year;
byte alarmHour = 0;                     // timestamp hour
byte alarmMinute = 0;                   // timestamp minute
byte alarmSecond = 0;                   // timestamp second
String alarmZone = "UTC";               // timestamp zone
// Next 6 variables are set on startup
byte bootMonth = 0;                    // timestamp month (1-12)
byte bootDay = 0;                      // timestamp day
int bootYear = 0;                      // timestamp year;
byte bootHour = 0;                     // timestamp hour
byte bootMinute = 0;                   // timestamp minute
byte bootSecond = 0;                   // timestamp second
String bootZone = "UTC";               // timestamp zone

/*
  EEPROM ADDRESSES
  Not stored as variables to save space
  0-12: bulb IDs
  32: bulb count
  64: timezone
  72: threshold
  80: hold time
  88: quiet hours
*/

EthernetClient client;
EthernetServer host(80);
EthernetUDP Udp;

byte eeprom_read(int addr = 0);
void eeprom_write(int addr = 0, byte value = 0);

void setup() {
  pinMode(sensorPower, OUTPUT);
  pinMode(LED_WARN, OUTPUT);
  pinMode(LED_STATUS, OUTPUT);
  pinMode(SPEAKER, OUTPUT);

  digitalWrite(sensorPower, LOW);

  Serial.begin(9600);
  //Serial.println("Initializing...");

  lan_connect();
  Udp.begin(8888);    // Listen on port 8888
  eeprom_read();       // sets bulb array
  send_ntp_packet();
  get_timestamp();

  // Set alarm timestamp, to be used as the restart time
  bootMonth = ntpMonth;
  bootDay = ntpDay;
  bootYear = ntpYear;
  bootHour = ntpHour;
  bootMinute = ntpMinute;
  bootSecond = ntpSecond;
  bootZone = zone;
}

void loop() {
  // Run sensors every 10 seconds, but keep the web server listening constantly

  curTime = millis();
  if (curTime - counter > 5000) {
    counter = curTime;
    // Flash the status light
    digitalWrite(LED_STATUS, HIGH);
    delay(50);
    digitalWrite(LED_STATUS, LOW);
    // Set toggle for sensor fetch to occur at (status interval * 2)
    sensorToggle = !sensorToggle;

    if (sensorToggle) {
      get_air_vals();
      get_water_vals();
      if (water) {
        // Figure out the age of water detection
        curSeconds = (alarmCount - 1) * 10;
        curMinutes = curSeconds / 60;
        curSeconds = curSeconds % 60;
        curHours = curMinutes / 60;
        curMinutes = curMinutes % 60;
      }
    }
  }

  EthernetClient webClient = host.available();
  if (webClient) {                                // If a new client connects
    //Serial.println(F("Client connected"));
    bool currentLineIsBlank = true;               // flag to determine if incoming data exists
    String data;                                  // stores request text

    while (webClient.connected()) {               // loop while the client is connected
      if (webClient.available()) {                // if there are bytes to read from the client
        char c = webClient.read();                // read a byte
        //Serial.write(c);
        data += c;                                // hold and collect all read bytes

        if (c == '\n') {                   // if the byte is a newline character
          if (currentLineIsBlank) {        // if current line is blank, that means two newlines in a row = end of header
            // Request is complete, so start the response
            webClient.println(F("HTTP/1.1 200 OK"));
            webClient.println(F("Content-type: text/html"));
            webClient.println(F("Connection: close"));

            // Header will be overwritten so capture important values first
            bool r_post = false;
            bool p_config = false;

            if (data.indexOf("POST") > -1) {
              r_post = true;
            }

            if (data.indexOf("GET /config") > -1) {
              p_config = true;
            }

            // Return some memory to the heap
            data = "";

            // Get the body data
            while (webClient.available()) {
              char b = webClient.read();
              //Serial.print(b);
              data += b;
            }
            //Serial.println(data);

            // Handle the request
            if (r_post) {
              // HANDLE POST REQUEST
              // Finish off the header
              webClient.println(F("Location: /saved"));
              webClient.println();

              // Parse the data and launch the result page
              if (data.indexOf("toggle") > -1) {
                // Post is from the status page
                parse_toggle(data);
                send_page_banner(&webClient);
                send_page_saved(&webClient, "/status");
              } else if (data.indexOf("tz") > -1) {
                // Post is from the config page
                data.replace("%5B%5D", "");
                parse_timezone(data);
                parse_threshold(data);
                parse_hold_time(data);
                parse_quiet_hours(data);
                parse_bulbs(data);
                send_page_banner(&webClient);
                send_page_saved(&webClient, "/config");
              } else {
                // Something went wrong
                //Serial.println(F("Unable to determine source of POST request"));
              }
            } else {
              // HANDLE GET REQUEST
              // Finish off the header
              webClient.println();
              send_page_banner(&webClient);
              // Load the correct page
              if (p_config) {
                send_page_config(&webClient);
              } else {
                send_page_status(&webClient);
              }
            }
            break;
          } else {
            currentLineIsBlank = true;
          }
        } else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }

    data = "";
    webClient.stop();
    //Serial.println(F("Client disconnected"));
  }
}

void parse_toggle(String &data) {
  // Extract and update alarm override
  if (data.indexOf("toggle=true") > -1) {
    alarmOverride = true;
  } else {
    alarmOverride = false;
  }
}

void parse_timezone(String &data) {
  // Extract and store timezone setting
  if (data.indexOf("tz") > -1) {
    if (data.substring(data.indexOf("=") + 1, data.indexOf("&")) == "1") {
      eeprom_write(64, 1);
    } else {
      eeprom_write(64, 0);
    }
  }
}

void parse_threshold(String &data) {
  // Extract and store alarm threshold setting
  byte pointer = data.indexOf("at=");
  if (pointer > -1) {
    // Need to check for out of bounds first, so a bad value won't get misinterpreted before filling the variable
    if (data.substring(pointer + 3, data.indexOf("&", pointer + 3)).toInt() > 255) {
      //alarmThreshold = 255;
      eeprom_write(72, 255);
    } else if (data.substring(pointer + 3, data.indexOf("&", pointer + 3)).toInt() < 0) {
      //alarmThreshold = 0;
      eeprom_write(72, 0);
    } else {
      eeprom_write(72, data.substring(pointer + 3, data.indexOf("&", pointer + 3)).toInt());
    }
    //eeprom_write(72, alarmThreshold);
  }
}

void parse_quiet_hours(String &data) {
  // Extract and store the quiet hours selection
  byte pointer = data.indexOf("q=");
  if (pointer > -1) {
    //Serial.println(data.substring(pointer+2, data.indexOf("&", pointer+2)));
    if (data.substring(pointer + 2, data.indexOf("&", pointer + 2)).toInt() == 1) {
      eeprom_write(88, 1);
    } else {
      eeprom_write(88, 0);
    }
  }
}

void parse_hold_time(String &data) {
  // Extract and store the alarm wait time
  byte pointer = data.indexOf("wt=");
  if (pointer > -1) {
    eeprom_write(80, data.substring(pointer + 3, data.indexOf("&", pointer + 3)).toInt());
  }
  //eeprom_write(80, holdTime);
}

void parse_bulbs(String &data) {
  // Extract and store activated bulbs
  // Append trailing & to body so processing the string works as expected

  int pointer = data.indexOf("b=");

  // Reset the bulb array to avoid duplicate entries
  memset(bulbIDs, 0, eeprom_read(32));

  if (pointer > -1) {
    //Serial.println(F("Found bulbs"));
    // Found some changes to make
    for (int i = 0; i < eeprom_read(32); i++) {
      bulbIDs[i] = data.substring(pointer + 2, data.indexOf("&", pointer + 2)).toInt();
      //Serial.print(F("Adding bulb to array: ")); Serial.println(bulbIDs[i]);
      pointer = data.indexOf("b=", pointer + 2);
      if (pointer == -1) {
        i = eeprom_read(32);
        //Serial.println(F("Out of bulbs to process"));
      }
    }
  } else {
    //Serial.println(F("No bulbs selected"));
  }
  // Save it all to NVRAM
  eeprom_write();
}

void get_water_vals() {
  // Get values for water and air
  // Trigger alarm if water is detected and override is disabled

  int level = read_sensor();
  //Serial.print(F("Raw water level: ")); Serial.println(level);

  if (level > eeprom_read(72)) {
    water = true;
    if (alarmCount == 0) {
      // Capture timestamp
      send_ntp_packet();
      get_timestamp();
      alarmMonth = ntpMonth;
      alarmDay = ntpDay;
      alarmYear = ntpYear;
      alarmHour = ntpHour;
      alarmMinute = ntpMinute;
      alarmSecond = ntpSecond;
      alarmZone = zone;
    }
    alarmCount++;

    //Serial.print(F("Threshold breached by ")); Serial.print(level - alarmThreshold);
    //Serial.print(F(" - Water detected for ")); Serial.print((alarmCount-1)*10); Serial.println(F(" seconds"));
    if (alarmOverride) {
      //Serial.println(F("Alarm override is enabled"));
    }
  } else {
    alarmCount = 0;
    water = false;
  }

  // Sound the alarm if water detected for configured threshold seconds
  if (alarmCount > eeprom_read(80)) {
    // Trigger the alarms (aural and visual) only if the manual override has not been set
    if (alarmOverride == false) {
      if ((eeprom_read(88)) == 1 && (localHour > 7) || eeprom_read(88) == 0) {
        String command = F("");
        // Loop through all the bulbs defined
        for (int i = 0; i < sizeof(bulbIDs); i++) {
          //Serial.print(F("Current bulb: ")); Serial.println(bulbIDs[i]);
          if (bulbToggle) {
            command = F("{\"on\": true,\"xy\": [0.1686, 0.2114],\"bri\":255,\"transitiontime\":0}");
          } else {
            command = F("{\"on\": false,\"transitiontime\":0}");
          }
          set_hue(bulbIDs[i], command);
          // Give the bridge some time before the next bulb commands
          delay(100);
        }
        bulbToggle = !bulbToggle;
        morse();
      }
    }
  }
}

byte read_sensor() {
  // Turn on the sensor and capture current water level, then turn off
  // Keeping the power off helps prolong the sensor's life
  byte val;
  digitalWrite(sensorPower, HIGH);
  delay(10);
  val = analogRead(sensorData);
  digitalWrite(sensorPower, LOW);
  return val;
}

void get_air_vals() {
  DHT dht(DHTPIN, DHTTYPE);
  dht.begin();

  float h = dht.readHumidity();
  float t = dht.readTemperature(true);

  if (isnan(h) || isnan(t)) {
    //Serial.println(F("Failed to read from DHT sensor"));
    h = -0;
    t = -0.0;
  } else {
    //Serial.print(F("Humidity: ")); Serial.print(h, 0); Serial.print(F("%"));
    //Serial.print(F(" Temperature: ")); Serial.print(t, 1); Serial.println(F("\xC2\xB0"));
  }
  humidity = h;
  temperature = t;
}

boolean set_hue(byte lightNum, String &command) {
  // Trigger the bulbs
  //const char hueUsername[] = "2vasdfa"; // Home
  const char hueUsername[] = "zxasdfasfd";  //Gail's
  if (client.connect(BRIDGE_IP, 80))
  {
    //Serial.println(F("Connected to hue for PUT"));
    while (client.connected())
    {
      client.print(F("PUT /api/"));
      client.print(hueUsername);
      client.print(F("/lights/"));
      client.print(lightNum);
      client.println(F("/state HTTP/1.1"));
      client.println(F("Connection: keep-alive"));
      client.print(F("Host: "));
      client.println(BRIDGE_IP);
      client.print(F("Content-Length: "));
      client.println(command.length());
      client.println(F("Content-Type: text/plain;charset=UTF-8"));
      client.println();  // blank line before body required to indicate end of header
      client.println(command);  // Hue command
      //Serial.println(F("Sent command to bridge"));
      delay(50);
      client.flush();
      client.stop();
    }
    return true;  // command executed
  }
  else
    //Serial.println(F("Hue PUT request failed"));
    return false;  // command failed*/
}

void send_page_status(EthernetClient *webClient) {

  // Show data
  webClient->println(F("<div style=\"float:left;width:51%;\">"));
  // Water data
  webClient->println(F("<h2>Current Water Status:</h2>"));
  if (water) {
    webClient->print(F("<p class=\"water\" style=\"margin-top:-3px;\"><b>Water detected </b><br />First detected ~"));
    // Display the age of water detection
    webClient->print(curHours);
    webClient->print(F( " Hours "));
    webClient->print(curMinutes);
    webClient->print(F(" Minutes "));
    webClient->print(curSeconds);
    webClient->println(F(" Seconds ago"));

    webClient->print(F("<br>Alarm triggered: "));
    print_alarm_time(webClient);

    if (alarmOverride == false) {
      if (alarmCount > eeprom_read(80)) {
        if ((eeprom_read(88) == 1) && (localHour < 8)) {
          webClient->println(F("<p><b class=\"warn\">Quiet hours active - Alarm will resume at 8am Eastern</b>"));
        } else {
          webClient->println(F("<p><b class=\"warn\">Alarm is activated</b>"));
        }
      } else {
        webClient->print(F("<p><b class=\"warn\">Alarm will activate after "));
        webClient->print(eeprom_read(80));
        webClient->print(F("0 seconds</b>")); // Hold time variable drops the 0
      }
    } else {
      webClient->println(F("<p><b class=\"warn\">Alarm suppressed by manual override</b>"));
    }
  } else {
    // No water detected
    webClient->print(F("<p class=\"status\" style=\"margin-top:-1px;\">Overflow pan is dry"));
    if (alarmMonth > 0) {
      webClient->print(F("<br>Water last detected: "));
      print_alarm_time(webClient);
    } else if (alarmMonth == 0) {
      webClient->print(F("<br>No water detected since last restart"));
    }
    if (alarmOverride == true) {
      webClient->print(F("<p><b class=\"warn\">Alarm override is enabled</b>"));
    }
  }

  // Display form to toggle override value
  // Form contains what would be the new value if submitted
  webClient->println(F("<form name=\"override\" action=\"/\" method=\"post\">\r\n"
                       "<input type=\"hidden\" name=\"toggle\" "));
  if (alarmOverride == false) {
    webClient->print(F("value=\"true\"><input type=\"Submit\" value=\"Enable Override\">"));
  } else {
    webClient->print(F("value=\"false\"><input type=\"Submit\" value=\"Disable Override\">"));
  }
  webClient->println(F("</form>"));

  webClient->print(F("<p>\r\n"
                     "Enabling override suppresses light and sound alerts when water is detected.<br />\r\n"
                     "It will not stop the detection process.\r\n"
                     "<p>\r\n"
                     "Disabling the override enables light and sound alerts. (Default setting)"));

  // Boot timestamp
  webClient->print(F("<hr style=\"width:50%; margin:0px;\">"));
  webClient->print(F("<p>Last Restart: "));
  webClient->print(bootMonth);
  webClient->print(F("/"));
  webClient->print(bootDay); webClient->print(F("/"));
  webClient->println(bootYear);

  // Show clock
  if (bootHour < 10) {
    webClient->print(F("0"));
  }
  webClient->print(bootHour); webClient->print(F(":"));
  if (bootMinute < 10) {
    webClient->print(F("0"));
  }
  webClient->print(bootMinute); webClient->print(F(":"));
  if (bootSecond < 10) {
    webClient->print(F("0"));
  }
  webClient->print(bootSecond);
  webClient->print(F(" "));
  webClient->print(zone);

  webClient->println(F("</div><div style=\"margin-left:50%;width:49%;\">\r\n"
                       "<h2>Room Temperature/Humidity:</h2><p class=\"water\" style=\"color:black;\">"));
  webClient->print(temperature, 1);
  webClient->print(F("&#xb0 / "));
  webClient->print(humidity);
  webClient->print(F("%</div></html>"));

}

void send_page_config(EthernetClient *webClient) {
  // Build the config page
  byte selectedCount = 0;   // Used to determine how many lights have been selected

  webClient->print(F("<form name=\"bulbchoice\" action=\"/config\" method=\"post\">\r\n"
                     "<table><tr><td><p>Timezone: \r\n"
                     "<select name=\"tz\" style=\"width:60px;\"><option value=\"0\""));
  if (eeprom_read(64) == 0) {
    webClient->print(F(" selected"));
  }
  webClient->print(F(">Local</option><option value=\"1\""));
  if (eeprom_read(64) == 1) {
    webClient->print(F(" selected"));
  }
  webClient->print(F(">UTC</option></select></td><td style=\"width:50px;\"></td>\r\n"
                     "<td><p>Alarm Threshold: \r\n"
                     "<input type=\"text\" style=\"width:40px;\" name=\"at\" value=\""));
  webClient->print(eeprom_read(72));
  webClient->print(F("\" /> (0-255)</td><td style=\"width:50px;\"></td>\r\n"
                     "<td><p>Alarm Wait Time: </td><td><p>\r\n"
                     "<select name=\"wt\" style=\"width:50px;\">"));

  for (int i = 3; i < 21; i = i + 3) {
    webClient->print(F("<option value=\""));
    webClient->print(i);
    webClient->print(F("\""));
    if (eeprom_read(80) == i) {
      webClient->print(F(" selected"));
    }
    webClient->print(F(">"));
    webClient->print(i);
    webClient->print(F("0</option>"));
  }

  webClient->print(F("</select> (seconds)</td></tr>\r\n"
                     "<tr><td colspan=\"5\"><p>Quiet Hours: <input type=\"radio\" name=\"q\" value=\"0\""));
  if (eeprom_read(88) == 0) {
    webClient->print(F(" checked"));
  }
  webClient->print(F(">No <input type=\"radio\" name=\"q\" value=\"1\""));
  if (eeprom_read(88) == 1) {
    webClient->print(F(" checked"));
  }
  webClient->print(F(">Yes (Alarm suppression between 12am and 8am local)</td></tr></table>\r\n"
                     "<table><tr><td colspan=\"3\"><p>Hue Bridge IP: "));
  webClient->println(BRIDGE_IP);
  webClient->println(F("</tr><tr><td><p>Alarm Lights:</td></tr>\r\n"
                       "<input type=\"hidden\" name=\"bulbs\" value=\"t\"><tr>\r\n"
                       "<tr><td><b class=\"warn\">2nd Floor</b></td></tr><tr>"));

  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"8\""));
  if (check_light_array(8)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Bed1</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"11\""));
  if (check_light_array(11)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Fan1</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"26\""));
  if (check_light_array(26)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Bed2</td></tr>"));
  webClient->println(F("<tr><td style=\"padding-top:10px;\"><b class=\"warn\">1st Floor</b></td></tr>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"13\""));
  if (check_light_array(13)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Kitchen1</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"3\""));
  if (check_light_array(3)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Kitchen2</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"22\""));
  if (check_light_array(22)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Hall</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"33\""));
  if (check_light_array(33)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Living</td></tr>"));
  webClient->println(F("<tr><td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"12\""));
  if (check_light_array(12)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Kitchen3</td>"));
  webClient->println(F("<tr><td style=\"padding-top:10px;\"><b class=\"warn\">Basement</b></td></tr>"));
  webClient->print(F("<tr><td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"4\""));
  if (check_light_array(4)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Basement1</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"15\""));
  if (check_light_array(15)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Basement2</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"9\""));
  if (check_light_array(9)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Basement3</td>"));
  webClient->print(F("<td class=\"cfg\"><input type=\"checkbox\" name=\"b[]\" value=\"10\""));
  if (check_light_array(10)) {
    webClient->print(F(" checked"));
    selectedCount++;
  }
  webClient->println(F(">Basement4</td>"));

  webClient->println(F("<tr><td><input type=\"Submit\" value=\"Save Changes\"></td></tr></table></form>"));

  if (selectedCount == 0) {
    webClient->println(F("<p>No lights have been selected.<br>\r\n"
                         "It is recommended to choose at least 1 light, then enable Alarm Override on the Status page."));
  } else if (selectedCount > 9) {
    webClient->println(F("<p>Performance may be impacted when more than 9 lights are selected."));
  }
}

bool check_light_array(int lightID) {
  // Find out if lightID is selected for alarming
  for (int i = 0; i < sizeof(bulbIDs); i++) {
    if (bulbIDs[i] != 0 && bulbIDs[i] == lightID) {
      //Serial.println(bulbIDs[i]);
      //Serial.print(F("Bulb IDs matches light id ")); Serial.print(bulbIDs[i]); Serial.print(F(" ")); Serial.println(lightID);
      return true;
    }
  }
  return false;
}

void send_page_saved (EthernetClient *webClient, String page) {
  // Display a success message after posting setting changes
  webClient->print(F("<p><b class=\"warn\">Changes Saved!</b><form action=\""));
  //Serial.println(page);
  webClient->print(page);
  webClient->print(F("\" method=\"get\"><input type=\"submit\" value=\"OK\"></form>"));
  // flush data to avoid repost
  webClient->print(F("<script>history.replaceState(null, document.title, location.href);</script>"));
}

void send_page_banner(EthernetClient *webClient) {
  // Prepare the common web header

  char months[13][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  // Get the time
  send_ntp_packet();
  get_timestamp();

  webClient->print(F("<!DOCTYPE HTML>\r\n"
                     "<html><head>\r\n"
                     "<link rel=\"icon\" href=\"data:,\">\r\n"
                     "<style> h1, h2 {color:black;font-family:Verdana}\r\n"
                     "p {font: 12px Verdana}\r\n"
                     "p.water {font: 16px \"Courier New\"; color:red}\r\n"
                     "p.status {color:black;font: 18px \"Courier New\"}\r\n"
                     "b {font-size:20px}\r\n"
                     "b.warn {font: bold 12px Verdana;color:steelblue}\r\n"
                     "a {font: 14px Verdana;position:relative}\r\n"
                     "a:link, a:visited {background-color:steelblue;color:white;padding:5px 6px 8px 4px;text-decoration:none;text-align:center;\r\n"
                     "display:inline-block;border-radius:14px;box-shadow:inset -3px -3px 5px #222;}\r\n"
                     "a:hover, a:active {background-color:lightseagreen;box-shadow:inset 1px 1px 4px #000;\r\n"
                     "top:1px;left:1px;text-shadow:1px 1px 1px #888;}\r\n"
                     "td.cfg {font: 12px Verdana;width:10%;}\r\n"
                     "td.head {padding-top:5px;}\r\n"
                     "</style>\r\n"
                     "<title>H2O Monitor</title></head><div style=\"background-image:linear-gradient(lightseagreen,steelblue);border-radius:5px\">\r\n"
                     "<body ontouchstart=\"\">\r\n"
                     "<table style=\"width:100%;padding:0px 5px 0px 5px;margin-top:-5px;\"><tr><td><h1>Water Heater Overflow Meter</h1></td>\r\n"
                     "<td style=\"width:20%;text-align:right;\"><h2 style=\"color:white;\">"));

  // Show clock
  if (ntpHour < 10) {
    webClient->print(F("0"));
  }
  webClient->print(ntpHour); webClient->print(F(":"));
  if (ntpMinute < 10) {
    webClient->print(F("0"));
  }
  webClient->print(ntpMinute); webClient->print(F(":"));
  if (ntpSecond < 10) {
    webClient->print(F("0"));
  }
  webClient->print(ntpSecond);
  webClient->print(F(" "));
  webClient->print(zone);

  webClient->print(F("</h2><p style=\"color:white;margin-top:-20px;font-size:16px;\">"));

  // Show date
  for (int i = 0; i < 4; i++) {
    webClient->print(months[ntpMonth - 1][i]);
  }
  webClient->print(F(" "));
  webClient->print(ntpDay); webClient->print(F(" "));
  webClient->print(ntpYear);

  webClient->print(F("</td></tr></table></div>"));

  // Navbar
  webClient->println(F("<div style=\"width:100%;display:block;\">\r\n"
                       "<table><tr>\r\n"
                       "<td><a href=\"/status?\" onclick=\"void(0)\">Status</a></td>\r\n"
                       "<td><a href=\"/config?\">Config</a></td>\r\n"
                       "</tr></table></div>"));
}

void get_timestamp() {
  TimeChangeRule dstRule = {"EDT", Second, Sun, Mar, 2, -240};
  TimeChangeRule stdRule = {"EST", First, Sun, Nov, 2, -300};
  TimeChangeRule *tcr;
  Timezone tz(dstRule, stdRule);

  // wait to see if a reply is available
  delay(200);
  if ( Udp.parsePacket() ) {
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, 48); // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;

    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;

    time_t eastern, utc;
    eastern = tz.toLocal(epoch, &tcr);
    if (eeprom_read(64) == 0) {
      epoch = eastern;
    }

    ntpMonth = month(epoch);
    ntpDay = day(epoch);
    ntpYear = year(epoch);
    ntpHour = hour(epoch);
    ntpMinute = minute(epoch);
    ntpSecond = second(epoch);
    // localHour used for quiet hours; always uses local time
    localHour = hour(eastern);
    if (eeprom_read(64) == 1) {
      zone = "UTC";
    } else {
      zone = tcr->abbrev;
    }

  } else {
    // NTP request not available
    //Serial.println(F("Failed to retrieve NTP time"));
  }
}

unsigned long send_ntp_packet() {
  // send an NTP request to the time server at the given address
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, 48);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket("time.nist.gov", 123); //NTP requests are to port 123
  Udp.write(packetBuffer, 48);
  Udp.endPacket();
}

void print_alarm_time(EthernetClient *webClient) {
  // Format and print the alarm timestamp
  webClient->print(alarmMonth);
  webClient->print(F("/"));
  webClient->print(alarmDay);
  webClient->print(F("/"));
  webClient->print(alarmYear % 100);
  webClient->print(F(" "));
  if (alarmHour < 10) {
    webClient->print(F("0"));
  }
  webClient->print(alarmHour);
  webClient->print(F(":"));
  if (alarmMinute < 10) {
    webClient->print(F("0"));
  }
  webClient->print(alarmMinute);
  webClient->print(F(":"));
  if (alarmSecond < 10) {
    webClient->print(F("0"));
  }
  webClient->print(alarmSecond);
  webClient->print(F(" "));
  webClient->print(alarmZone);
}

void morse() {
  // Beep out L-E-A-K in Morse code

  const byte DOT = 50;      // 1 time unit
  const byte DASH = DOT * 3;
  const byte SYMBOL = DOT;
  const byte LETTER = SYMBOL * 3;
  const byte WORD =  SYMBOL * 7;
  const byte PHRASE = WORD * 2;

  // All letters have at least one pulse; at most 4
  int code[4][4] = {{DOT, DASH, DOT, DOT}, {DOT}, {DOT, DASH}, {DASH, DOT, DASH}};

  // i loops through the letters
  // j loops through the pulses in each letter
  for (byte i = 0; i < 4; i++) {
    for (byte j = 0; j < 4; j++) {
      if (code[i][j] != 0) {
        tone(SPEAKER, 1500);
        digitalWrite(LED_WARN, HIGH);
        delay(code[i][j]);
        noTone(SPEAKER);
        digitalWrite(LED_WARN, LOW);
        delay(SYMBOL);
      }
    }
    delay(LETTER);
  }
  delay(PHRASE);
}

void lan_connect() {
  // Use DHCP to connect, then verify connection
  byte mac[] = {0x05, 0x22, 0x13, 0x35, 0xFF, 0xBA};

  //Serial.print(F("Obtaining IP address..."));
  if (Ethernet.begin(mac) == 0) {
    //Serial.println(F("Failed to configure Ethernet using DHCP"));
  }
  //Serial.println(Ethernet.localIP());
  //Serial.print(F("Verifying connection..."));
  bool cnxTest = false;
  byte cnxCount = 0;
  while (cnxTest == false) {
    if (cnxCount < 3) {
      if (client.connect(Ethernet.gatewayIP(), 80)) {
        cnxTest = true;
        //Serial.println(F("OK"));
      } else {
        cnxCount++;
        //Serial.print(F("FAIL, retrying... "));
      }
    } else {
      //Serial.println(F("Connection failed to establish"));
      break;
    }
  }

  // Only needed connection for testing, so shut it down now
  client.flush();
  client.stop();
}

void eeprom_write(int addr, byte value) {
  // Save data to non-volatile memory
  if (addr == 0) {
    // Saving bulb selection
    for (addr; addr <= eeprom_read(32); addr++) {
      //Serial.print(F("Writing to memory: ")); Serial.print(addr); Serial.print(F(" ")); Serial.println(bulbIDs[addr]);
      EEPROM.update(addr, bulbIDs[addr]);
    }
  } else {
    // Saving other settings
    //Serial.print(F("Writing to memory: ")); Serial.print(addr); Serial.print(F(" ")); Serial.println(value);
    EEPROM.update(addr, value);
  }
}

byte eeprom_read(int addr) {
  // Read data from non-volatile memory
  byte value = 0;
  if (addr == 0) {
    for (addr; addr <= eeprom_read(32); addr++) {
      value = EEPROM.read(addr);
      //Serial.print(F("Reading from address: ")); Serial.print(addr);
      //Serial.print(F(" ")); Serial.println(value);
      bulbIDs[addr] = value;
    }
  } else {
    value = EEPROM.read(addr);
    return value;
  }
}

A big and complicated sketch for a first project!

IF you have used exactly and only this code, in an otherwise empty sketch

#define sensorData A5
int val;

void setup() {
  Serial.begin(9600);
    Serial.println("Initializing...");
    val = analogRead(sensorData);
    Serial.println("After read");
}

with an empty loop{}

and are getting the results you show

I can only conclude there is a fault on the Arduino board.

First C++, but not first programming... :slight_smile:

Your idea is a good one -- prior to posting I put the simple test code inside of the existing sketch. So I took everything out and only ran that snippet. Indeed the result was the same with a crash and a hang.

Can't imagine what caused this but I guess I'll have to try another board. Bummer.

Thanks for the replies!

I would change the line to Serial.print(analogRead(sensorData)); because the code does not print the A/D reading. I have short pieces of simple code to check each of the hardware devices I have. I know the code is good and it has been tested. I simply run that to check the hardware. Save this piece of code to check A/D. Post a schematic, not a frizzy thing showing all connections.

Thanks for the suggestion. I tried the following, once for each analog pin A0-A5:

#define sensorData A2
void setup() {
  Serial.begin(9600);
  Serial.println("Initializing");
  Serial.println(analogRead(sensorData));
  Serial.println("Done");
}

void loop() {
  
}

Each time, I get the same:

22:11:34.787 -> Initializing
22:11:36.490 -> Initializing

This is the schematic. I'm not an electrical engineer, nor do I play one on TV, but it's the best I could come up with.

schemeit-project (5)

Nice diagram @brickwins - I'm interested, what did you use to produce it?

Silly question - have you tested the board with all connections removed?

Also your resistor values as shown on the diagram would not work.

Thanks. Digikey has a free editor on their web site called scheme-it.

I removed all analog connections and got the same result. Followed that by pulling everything else out so the only connection was power via USB. Same result.

Which resistors in the schematic are wrong? I’m fairly certain that is how I connected everything. Maybe I transposed one of the values incorrectly? Or are you suggesting something else?

Your LEDs would not be very bright (understatement for dramatic effect) with resistors in the hundreds of k!
and a 10 ohm series to the piezo ...?

Scheme-it .. interesting I'll have to give it a more extensive try; it wouldnt give me a symbol for a transistor!

Oops! I am actually using a 1k on the white LED and a 330 on the blue one. Both are plenty bright because they differ from that schematic.

The piezo resistor… as I am new to this and started with LED fun, I ended up with this sense that resistors should be everywhere. I’d like to think I saw a recommendation for using one with a piezo but I don’t know if I actually did. I put the 10 Ohm on it because anything more made it too quiet.

As I said earlier: pants went on before the underwear. I guess my programming experience equates to the pants; electricity is the other. But eventually we all learn how to dress ourselves!

It seems to me it's in an endless (?) Reset.
That's why it keeps "Initializing".
Disconnect everything and see what happens.
Assuming it comes right, re-connect the items one thing at a time till the trouble comes back.

#define sensorData A2

int Data ;

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing");

Data =(analogRead(sensorData));

  Serial.println(Data);
  Serial.println("Done");
}

void loop() {
  
}

Try this to see if it gets beyond "Initializing .

so..
the Uno crashes when you attempt an analog read();
it DOES progress to the Serial print, and prints "initialising"
it is a very fast process to that point

I dont think it would progress to that point with a permanent hard reset - eg a short circuit.
Its looking like its bricked - but a few last questions.
Does it work properly for a longer program if you DONT do an analog read? Eg the blink without delay sketch?
(trying to eliminate the possibility of a delayed reset from somewhere)
Does the BWOD sketch work if you then include serial printing?

If I leave the entire sketch as is, but don't make the call to get_water_vals() from the loop, everything functions normally (i.e., the web server) except that the call to get_air_vals() doesn't return anything. The difference between _water and _air is that the former includes an explicit analogRead() while the latter uses the DHT library. I have no idea how that library handles data input.

I did load the BWOD example and it works fine both with and without Serial printing.

To @runaway_pancake, regarding removing inputs, this is all happening whether or not anything is connected to any of the analog inputs. And @cherk suggestion resulted in the same crashing behavior.

You're saying that with nothing connected you just get repetitions of "Initializing..." on SerialMonitor?

With nothing connected, I get "Initializing" exactly twice, about 2 seconds apart. The board appears to hang after the second one.

That bodes ill.
Will it still do "Blink"?

PE - Did you do anything to/with AREF ?

Blink works. Haven't touched AREF.

Interesting.
What if sensorRead is changed to a different pin (A3) [and nothing connected still]?

PE - Your setup() executes, partially, twice:(resulting the two "Initializing...", never getting to the "After Read" print part, and then something goes mucho awry.
PPE - And why was/is the 'water sensor' powered by A4?

#define sensorData A5                 // Water sensor data pin
#define sensorPower A4                 // Water sensor power pin