Things used in this project

Hardware components:
Photon new
Particle Photon
×1
Adafruit industries ada161 image 75px
Photo resistor
×2
Mfr 25frf52 10k sml
Resistor 10k ohm
×2
Hand tools and fabrication machines:
09507 01
Soldering iron (generic)

Schematics

Laundry Monitor Schematic
Use a breadboard or solder it up.

Code

Laundry MonitorC/C++
Create a new Photon project and use this code for the .ino file
/*
 * Project Laundry Monitor
 * Description: Washer / Dryer monitor and notifications
 * Author: Martin Smaha
 * Date: 3/9/2017
 */
#include <string.h>

 TCPServer server = TCPServer(8080);//web page port
 TCPClient client;
 char LANBuf[1026],pBuf[128];
 int LED = D7;
 int washerAnalogPin = A0;
 int dryerAnalogPin = A1;

 bool isWasherRunning;
 bool isDryerRunning;
 unsigned long WasherRunTime_sec;
 unsigned long DryerRunTime_sec;
 unsigned long msecLast;
 int washerValue;
 int dryerValue;

 void WebHeader(void);
 void WebServer(void);
 void FormatRuntime(unsigned long xSeconds);

// setup() runs once, when the device is first turned on.
void setup() {
  // start listening for clients
  server.begin();
  // small blue LED on board
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  // variables
  LANBuf[0] = 0;
  msecLast = millis();
  washerValue = 0;
  dryerValue = 0;
}

// loop() runs over and over again, as quickly as it can execute.
void loop() {
  WebServer();
  unsigned long msec = millis();
  if (msec > msecLast) {
    unsigned long diff = msec - msecLast;
    if (diff >= 1000) {
      ReadAnalogs();//only read them once per second
      diff -= 1000;
      msecLast = msec - diff;
    }
  } else {
    msecLast = msec;// this throws away 1 millisecond every 49 days due to wrapping
  }
}

// Web Header
void WebHeader(void) {
  client.print("HTTP/1.1 200 OK\r\n\r\n<html><head><title>Laundry</title><style>div {border: 2px solid #a1a1a1;padding: 10px 40px;width: 200px;border-radius: 25px;}button {width: 100px;height: 40px;background: blue;color: white;}button:hover {color: black;}</style>");
  client.print("<META HTTP-EQUIV='Pragma' CONTENT='no-cache'>");
  client.print("<META HTTP-EQUIV='Expires' CONTENT='-1'>");
  client.print("<meta content='text/html; charset=ISO-8859-1' http-equiv='Content-Type'>");
  client.print("<meta name='viewport' content='width=device-width, initial-scale=1'></head>");
}

// Web server
void WebServer(void) {
  if (client.connected()) {
    int isRequest = -1;
    if (client.available()) { //get first data segment
      memset(LANBuf,0,sizeof(LANBuf));//clear old data
      client.read((uint8_t*)LANBuf,sizeof(LANBuf) - 2);//leave the buffer zero terminated
      //determine which page browser has requested
      if (strstr(LANBuf,"GET") != NULL) {
        isRequest = 0;
      }
      if (strstr(LANBuf,"status.html") != NULL) {
        isRequest = 1;
      }
    }
    //send response
    if (isRequest == 0) { //standard http error message for page not found
      client.print("HTTP/1.1 404 \r\n\r\n");
      client.stop();
    }
    if (isRequest == 1) { //status.html
      WebHeader();
      client.print("<body bgcolor=#ffffff width=250px><div><h1>Laundry</h1><table>");
      // status LEDs
      if (isWasherRunning) {
        client.print("<tr><td><span style=background:#00ff00;> &nbsp &nbsp </span></td><td><font>Washer</font></td>");
        FormatRuntime(WasherRunTime_sec);
        client.print(pBuf);
      } else {
        client.print("<tr><td><span style=background:#cccccc;> &nbsp &nbsp </span></td><td><font>Washer</font></td><td>OFF</td>");
      }
      client.print("</tr><tr><td>&nbsp</td><td>&nbsp</td><td>&nbsp</td></tr>");
      if (isDryerRunning) {
        client.print("<tr><td><span style=background:#00ff00;> &nbsp &nbsp </span></td><td><font>Dryer</font></td>");
        FormatRuntime(DryerRunTime_sec);
        client.print(pBuf);
      } else {
        client.print("<tr><td><span style=background:#cccccc;> &nbsp &nbsp </span></td><td><font>Dryer</font></td><td>OFF</td>");
      }
      client.print("</tr></table>");
      //diagnostic section. Comment out this section once analog values have been adjusted
      sprintf(pBuf,"<hr><p>Washer: %d<br>Dryer: %d</p>",washerValue,dryerValue);
      client.print(pBuf);
      //end diagnostic section
      client.print("</div></body></html>");
      client.stop();
    }
  } else {
    // if no client is yet connected, check for a new connection
    client = server.available();
  }
}
void ReadAnalogs(void) {
  washerValue = analogRead(washerAnalogPin);  // read the analogPin
  bool isON = (washerValue < 1024);
  if (isWasherRunning) {
    if (isON) {
      WasherRunTime_sec++;
    } else {
      isWasherRunning = false;
      if (WasherRunTime_sec >= 60) { //prevents notifications when cycling thru timer
        Particle.publish("LAUNDRY","Washer Done",60,PRIVATE);
      }
    }
  } else {
    if (isON) {
      isWasherRunning = true;
      WasherRunTime_sec = 0;
    }
  }
  dryerValue = analogRead(dryerAnalogPin);  // read the analogPin
  isON = (dryerValue < 1024);
  if (isDryerRunning) {
    if (isON) {
      DryerRunTime_sec++;
    } else {
      isDryerRunning = false;
      if (DryerRunTime_sec >= 60) { //prevents notifications when cycling thru timer
        Particle.publish("LAUNDRY","Dryer Done",60,PRIVATE);
      }
    }
  } else {
    if (isON) {
      isDryerRunning = true;
      DryerRunTime_sec = 0;
    }
  }
  if (isWasherRunning || isDryerRunning) { //used of initial testing
    digitalWrite(LED, HIGH);
  } else {
    digitalWrite(LED, LOW);
  }
}

void FormatRuntime(unsigned long xSeconds) {
  unsigned int hours;
  unsigned int minutes;
  unsigned int seconds;
  hours = xSeconds / 3600;
  xSeconds -= hours * 3600;
  minutes = xSeconds / 60;
  xSeconds -= minutes * 60;
  seconds = xSeconds;
  sprintf(pBuf,"<td><font>ON for %dh %dm %ds</font></td>",hours,minutes,seconds);
}

Credits

183193 102389716507771 4133659 n rhhfeodpxv
Martin Smaha

Designing hardware and software since 1975.

Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

WiFi Strength Meter
Easy
  • 665
  • 11

A meter that indicates the Wi-Fi signal strength in an intuitive way, using the parts I had on hand.

E-Paper Weather Display with Photon and IFTTT
Easy
  • 4,985
  • 25

Full instructions

Create a beautiful medium for weather information using Particle's cloud services and IFTTT.

2-Way Particle Photon Communication
Easy
  • 210
  • 4

Make two Particle Photons "talk" via the usage of webhooks!

IFTTT - Enabled Sensors with Particle Photon
Easy
  • 744
  • 11

Full instructions

Connect any sensor to Particle Photon and use it to trigger an IFTTT action with just a few lines of code.

Light Detecting Email Sender
Easy
  • 248
  • 4

Full instructions

Receive an email about when the light is too strong on your device; nobody wants a heated device left directly under the sun. Photon + IFTTT

Internet-Connected Popcorn Popper
Easy
  • 172
  • 1

Full instructions

A hot air popcorn popper triggered via the Internet! (Built for the Bellingham Codes May event.)

Sign up / LoginProjectsPlatformsTopicsContestsLiveAppsBetaFree StoreBlog