Project tutorial
Laundry IFTTT Alert

Laundry IFTTT Alert © GPL3+

Make laundry machines let you know when they are done, non-invasive automatic start with IFTTT call at end of cycle.

  • 5,309 views
  • 1 comment
  • 13 respects

Components and supplies

Apps and online services

About this project

Our laundry machines are in the basement, when we remodeled our 1932 two story home, the staircases were sound insulated. The cute chirping of our front loading machines doesn't stand a chance of cutting through. My wife mentioned that our machines have some sort of phone connection for servicing, she asked why can't they tell her when the cycle is complete.

That started the build.

I had a couple Wii nunchucks from a broken Wii, they have motion sensors in them. A quick web search found an instructable http://www.instructables.com/id/Washer-Dryer-Laundry-Alarm-using-Arudino-SMS-Text-/?ALLSTEPS using a Arduino Yun, it was quite helpful, I had an Uno with an Ethernet card.

That started the build, which is straightforward. 4 wires from a Wii Nunchuck, and a few LED's to see what's going on, tweak the numbers to the machine and the laundry is IFTTT connected..

What about that other way

Before going too far, let's consider different methods of grabbing an alert an Arduino could respond to. Vibration, current, and sound were all possibilities. I liked a current sensing method best, it however requires dealing with line voltages, even with an inductive sensor. The NEC is going to require the sensor be in a junction box. In my case both the washer and dryer are on independent circuits, so the main panel would be a fine place for the sensors. Since I designed and wired the whole lot, that method fits me quite well, for this project a blog post was one of the goals.

The main electrical panel method would limit the audience. So as MakerBee considered, a noninvasive solution fits the bill better. Vibration seemed better than sound to me, the variety of beeps and boops from today's electronic equipment seemed more difficult to decrypt.

Nunchuck and more, requirements

A nunchuck is a pretty inexpensive method to get a motion controller wired up ready to go. A little desoldering yields a nice starting point. Most of my laundry experience is with top load washers. They vibrate to beat the band, the front loader we have now, doesn't move very much. Of course when it spins, that all changes, but most of the time it just smoothly goes about its business. The nunchuck sensor is impressive, it easily picks up the slightest movement. Tapping one's fingers lightly on a sturdy desk, a couple feet away is discernable.

Another requirement was an auto start function. I want the device to be hands off, it should notice the machine is running, monitor it until complete and fire off a text message. The dryer monitor shouldn't auto start during a washer cycle, and vice versa. Lastly the device should indicate what's it is doing through a couple LED's.

The build, thanks to the nunchuck library is pretty easy.

Parts needed for one unit

1 - Arduino Uno

1 - Ethernet Shield

2 - Momentary contact buttons

4 - LED's different colors. (Red, Green, Blue, Yellow)

2 - about 2K Resistors

1 - Wii Nunchuck, maybe with a nunchuck breakout board.

1 - Case

1 - Neodymium magnet (hard drive salvage)

1 - Arduino nunchuck library Misc other standard building things, wire, breadboard

You may need another resistor. The red and blue LED's needed them, for some reason the yellow did not, and the green is typically held down by the program. I'm not an EE, but that side of me says both yellow and green should have a series resistor, maybe smaller on green. The buttons are not shown on the diagram, extend them from the nunchuck circuit board. The button module has 3 wires, a common and one for each button. The nunchuck is a 3.3 volt device. Read all about the nunchuck at https://create.arduino.cc/projecthub/infusion/using-a-wii-nunchuk-with-arduino-597254

I started by cutting the plug off the nunchuck and installing DuPont connectors onto the wires.

Those were plugged into the Ethernet Shield sitting on top of the Uno. That is really all that is needed for this project, the LED's are fluff or as a friend says, everyone sells steak, that's the sizzle. When using an Ethernet Shield, don’t use pins 10 through 13, also sometimes pin 8 gets involved in network connections.

You should know, I'm quite new to Arduino, electronic design and Arduino code, I can solder, so take my notes like you read it on the internet.

The LED sequence and usage are.

  • Blue, comes on during POST then off when running.
  • Blue turns on consider starting, turns back off it's done considering for now. Turns on at the half way point.
  • Yellow, the system automatically started.
  • Green, the system is running.
  • Red, consider stopping, turns off it's done for now. turns on at 10% of the way there.
  • Red turns off when network transmission to ifttt starts.
  • Yellow turns off when network transmission to ifttt ends.
  • Green turns off when cycle complete.

When adding LED's I found only the blue and red one's needed series resistors. The yellow one was already not too bright / about to smoke. The green one's level is held down during the Arduino loop, then it goes overdriven when a network transmission is taking place.

Nunchuck buttons are used as optional start or stop functions. Each laundry machine got its own device which share a common code base. Adding a couple transistors and tweaking the code would allow 2 nunchucks to live on the I2C protocol.

Configuration and Process Description

Each machine has it's own variable for each of the settings. The variable IsWasherDryer is used to control which machine the code is for. Set it to True for the washer and False for the dryer.

Auto Start Process

The Arduino is checking the sensor about 84 times a second. The motion sensor in the nunchuck is quite sensitive with the ability to see a rather light finger roll a couple feet away on a heavy desk. The movement information comes in as an integer between 0 and 254. The finger roll gives one or two of the 3 sensors a visible change. When the machine starts shaking the device starts up.

The start movement threshold is called AutoStartSensitivity. With such a rapid refresh rate and small movements, the sensors report no movement sometimes. This is handled with a variable AutoStartThreashold. That last variable defined for automatic starting is how long the device needs to be moving before it's an official start. That is called AutoStartMovementTime.

Ideally the device would start near the begin cycle of the machine, however with really smooth front loading washers, it might be better to start at the first spin cycle. The Dryer has a much more consistent vibration, and is easy to automatically start. The dryer's AutoStartMovementTime should be longer than the washer's spin cycle, or at least the violent part of it.

The Serial Log can be watched to tweak these settings. During Auto Start, it will scroll vertically if the AutoStartSensitivity is not reached. As that level is reached the log will begin to wrap 10 loops on a line. During a run, the log changes to showing the maximum movement received in about a second. It is useful when adjusting the automatic start settings to manually start run mode to watch the movement.

Run Process

Once we're started, we have two variables to control the run process. RunSensitivity, which is looking at movement like AutoStartSensitivity. The other option is used to determine the end of the cycle and called RunWaitTime. That is how many minutes of no movement before the ifttt post is made. For my machines the dryer RunWaitTime is short, 30 seconds or so, the washer has a much longer delay, a few minutes.

The ifttt post, has a Maker listener with an event name set to match the machine's IftttEventName. Your personal ifttt Key goes in iftttKey. Other than key, each of the above variables has a washer and dryer setting.

There are a couple test settings. isTestMode is used to not fire the ifttt event, isFastMode is an integer divider on the timers for easy desktop testing. Each device has a MAC and IP address setting, they should not be duplicated. The rest of the settings are, for what pins the LED's are connected, a timerAdjustment which can be changed to define what a minute is, and finally the baud rate to talk with the serial monitor. The nunchuck Z button is Start while C is stop.

These are currently in operation, and working great. It took over 10 laundry loads to get the settings correct. I watched a number of full cycles monitoring the serial monitor for feedback. Load size and selected options on the machines vary quite a bit. When setting autostart it is useful to manually enter run mode to see a different output on the serial monitor.

The End

edit-I forgot to mention the Neodymium magnet, it is used to provide a better connection to the machine. I used a decent sized one, which can be seen the the Completed Build picture, JB Welded to the bottom of the case. If you have small one's use two. We want to be fairly well connected, like a dictionary was place on top of the device. A hard drive salvage magnet 1-1/2" by 1/2" by 1/8" worked well.

I hope you enjoy it as much as we do. Having the washer or dryer mention it's completed awesome. Good luck to you and stop by danvanfleet.com for a visit.

Code

Laundry Machine to IFTTTArduino
Monitors laundry machines through discarded (or new) Wii Nunchucks. Automatically starts, monitors the cycle then fires an IFTTT event when complete.
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>
#include <Wire.h>
#include <ArduinoNunchuk.h>
/*
  Washing Machine Control
   Copyright 2016 Dan Van Fleet http://danvanfleet.com
 
   Project URL: None Yet
   Monitor machine for movement to automatically start, monitor cycle, send IFTTT event at end of cycle.
   Uses Wii Nunchuck for motion and buttons as manual start and cancel buttons.
*/
const bool isWasherOrDryer = false ; // true for washer, false for Dryer
const bool isTestMode = false;  // true won't fire IFTTT integration
const int isFastMode = 1; // used for testing divides timers by entered value.  0 or 1 runs normal time.
 
const String washerIftttEventName = "WasherDone";
const String dryerIftttEventName = "DryerDone";
const String iftttKey = "PutYourIFtttKeyHere";
const char server[] = "maker.ifttt.com";
 
byte dryerMac[] = { 0xDA, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE };
byte washerMac[] = { 0xDA, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const IPAddress dryerIP(192, 168, 16, 177);  // Set the static IP address to use if the DHCP fails to assign
const IPAddress washerIP(192, 168, 16, 178);  // Set the static IP address to use if the DHCP fails to assign
 
/*
 
  These settings are for a Front Loading Kenmore Elite washer and dryer sitting on a drawer on concrete. 
  The dryer is rather a consistent vibration, and significantly larger than the washer other than spin cycle.
  The washer stops for a fairly long period of time and has a high RunWaitTime in comparison.
  DryerAutostartMovement time should be longer than Washer Spin cycle.
  Washer AutoStart could be set fairly high to startup during the wash spin cycle rather than close to initial startup.
*/
 
const int washerRunSensitivity = 4; // movement sensitivity, lower more sensitive 1 - 255
const float washerRunWaitTime = 4.1;  // minutes set to maximum no movement time during a run, at the end the event is fired.
 
const int washerAutoStartSensitivity = 3;  //movement sensitivity for automatic start, can be set big to get caught by first spin cycle
const float washerAutoStartMovementTime = 60; // Seconds movement required before auto start
const int washerAutoStartThreshold = 250; // skips # of not breaking sensitivity allowed during autostart
 
const int dryerRunSensitivity = 6; // movement sensitivity, lower more sensitive 1 - 255
const float dryerRunWaitTime = 0.5;  // minutes set to maximum no movement time during a run, at the end the event is fired.
 
const int dryerAutoStartSensitivity = 4;  //movement sensitivity for automatic start
const float dryerAutoStartMovementTime = 480; // Seconds movement required before auto start, needs to be longer than washer's fast spin cycle
const int dryerAutoStartThreshold = 85; // skips # of loops reading lower than sensitivity allowed during autostart
 
const int pinRun = 4;  // Pin Run LED is connected to Green.  Illumiate 50% during run, 100% during ifttt send.
const int pinAutoStartCheck = 7; // Pin AutoStart in progress LED Blue.  Illuminates at 50% of AutoStartMovementTime. Flashes at initial power up, after post.
const int pinEndCycleCheck = 6;  // Pin End Cycle check LED Red. Illuminates at 10% of RunWaitTime.
const int pinAutoStarted = 5;  //Pin cycle was autostarted LED Yellow. Illuminates when autostart detected.
 
const int timerAdjustment = 5000; // loops per minute
const int BAUDRATE = 19200;
// End Setup items
 
ArduinoNunchuk nunchuk = ArduinoNunchuk();
bool isRunning = false;  // program contol
float lastAccelX = 0;  // stores last positions for delta determinations.
float lastAccelY = 0;  // ''
float lastAccelZ = 0;  // ''
int counter = 0;  // stores counter position for run loop counter
float startMoveCounter = 0;  // stores counter position for auto start cycle loops
int lastChangeCount = 0;  // stores counter position of last seen change
// these come from washer or dryer settings.
int runSensitivity = 0; // stores minimum movement value to continuing running.
float runWaitTime = 0; // stores maximum no movement time in seconds before run ends
int autoStartSensitivity = 0; // stores minimum value to consider starting
float autoStartMovementTime = 0; // stores seconds of start movement before auto start
int autoStartThreshold = 0; // stores maximum no movement loops to ignore during auto start check.
String iftttEventName = ""; // stores ifttt event name to run
byte mac[]  = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // placeholder for mac address
IPAddress ip(192, 168, 16, 175);  // place holder for IP address //end washer or dryer settings
int logX = 0; // Used for Display
int logY = 0;
int logZ = 0;
int countWrap = 0;
int displayWrap = 0; // end Display
EthernetClient client; // used to talk
 
void setup()
{
   pinMode(pinRun, OUTPUT);
  pinMode(pinAutoStartCheck, OUTPUT);
  pinMode(pinEndCycleCheck, OUTPUT);
  pinMode(pinAutoStarted, OUTPUT);
  digitalWrite(pinRun, LOW);
  digitalWrite(pinAutoStartCheck, HIGH);
  digitalWrite(pinEndCycleCheck, LOW);
  digitalWrite(pinAutoStarted, LOW);
  Serial.begin(BAUDRATE);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  nunchuk.init();
   
  if (isWasherOrDryer) // toggle in variables
  {
    runSensitivity = washerRunSensitivity;
    runWaitTime = washerRunWaitTime;
    autoStartSensitivity = washerAutoStartSensitivity;
    autoStartMovementTime = washerAutoStartMovementTime;
    autoStartThreshold = washerAutoStartThreshold;
    iftttEventName = washerIftttEventName;
    memcpy(mac,washerMac,  6);
    memcpy(ip, washerIP, 4);
  }
  else
  {
    runSensitivity = dryerRunSensitivity;
    runWaitTime = dryerRunWaitTime;
    autoStartSensitivity = dryerAutoStartSensitivity;
    autoStartMovementTime = dryerAutoStartMovementTime;
    autoStartThreshold = dryerAutoStartThreshold;
    iftttEventName = dryerIftttEventName;
    memcpy(mac, dryerMac, 6);
    memcpy(ip, dryerIP, 4);    
  }
  if (isFastMode > 1) {
    runWaitTime = runWaitTime / isFastMode;
    autoStartMovementTime = autoStartMovementTime / isFastMode;
  }
}
void loop()
{
  // if there are incoming bytes available
  // from the ifttt server, read and print them:
  if (client.available()) {
    digitalWrite(pinAutoStartCheck, LOW);
    char c = client.read();
    Serial.print(c);
  }
  else {
    nunchuk.update();
    CheckButtons();
    if (isRunning == true)
    {
      digitalWrite(pinAutoStartCheck, LOW);
      digitalWrite(pinRun, HIGH);
      if (counter < (runWaitTime * timerAdjustment)) { RunMovementInspector(); digitalWrite(pinRun, LOW); // keeps LED dimmer so that when ifttt call is being setup and made it gets brighter. 
  {
    // Movement detected
    counter = 0;
    digitalWrite(pinEndCycleCheck, LOW);
  }
  else
  {
    //Not moving, should we get out?
    counter++;
    if (counter > runWaitTime * timerAdjustment / 10)
    { // Light the considering stop light at
      digitalWrite(pinEndCycleCheck, HIGH);
    }
  }  
  PrintLog(counter, changeX, changeY, changeZ);
  
}
 
int GetChangeX(){
  float accel = nunchuk.accelX;
  float change = lastAccelX - accel;
  lastAccelX = accel;
  return abs(change);
}
int GetChangeY(){
  float accel = nunchuk.accelY;
  float change = lastAccelY - accel;
  lastAccelY = accel;
  return abs(change);
}
int GetChangeZ(){
  float accel = nunchuk.accelZ;
  float change = lastAccelZ - accel;
  lastAccelZ = accel;
  return abs(change);
}
void StartupCheck()
{
  float changeX, changeY, changeZ;
  changeX = GetChangeX();
  changeY = GetChangeY();
  changeZ = GetChangeZ();
  if ( changeX > autoStartSensitivity ||  abs(changeY) > autoStartSensitivity || abs(changeZ) > autoStartSensitivity )
  { // Something  moved more than it should have, count it.
    startMoveCounter++;
    lastChangeCount = startMoveCounter;
    StartupLog(startMoveCounter, changeX, changeY, changeZ);  
    if (startMoveCounter > (autoStartMovementTime * timerAdjustment / 120)) {
      digitalWrite(pinAutoStartCheck, HIGH); // if we hit half way point light the led. 
    }
  }
  else
  {
    if (startMoveCounter - lastChangeCount > autoStartThreshold) {
      //too many counts since change detected, reset counters
      startMoveCounter = 0;
      lastChangeCount = 0;
      digitalWrite(pinAutoStartCheck, LOW);
      Serial.println("Reset Counters");
    } else
    {
      startMoveCounter++;
      Serial.println(startMoveCounter, 0);  // we didn't move, print a line
    }
  }
  if (startMoveCounter > (autoStartMovementTime * timerAdjustment / 60 ))  //autoStartMovementTime is in Seconds.
  {
    isRunning = true;
    digitalWrite(pinRun, HIGH);
    digitalWrite(pinAutoStarted, HIGH);
    startMoveCounter = 0;
  }
}
void SendAlert()
{
  // start the Ethernet connection:
  Serial.println("starting");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
 
  Serial.println("connecting...");
  if (client.connect(server, 80)) {
    Serial.println("connected");
    //Make a HTTP request:
    client.println("GET /trigger/" + iftttEventName + "/with/key/" + iftttKey + " HTTP/1.1");
    client.println("Host: maker.ifttt.com");
    client.println("Connection: close");
    client.println();
  }
  else //client.connect
  {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}
void PrintLog(int counter, int changeX, int changeY, int changeZ)
{
  int summary = 99;  // 83 is closer to a second 100 is easier to read
  displayWrap++;
  // Display largest change over summary movements
  if (countWrap < summary) {
    if (logX < changeX) {
      logX = changeX;
    }
    if (logY < changeY) {
      logY += changeY;
    }
    if (logZ < changeZ) { logZ += changeZ; } countWrap++; } else { Serial.print(counter); Serial.print("-"); Serial.print(logX); Serial.print(" "); Serial.print(logY); Serial.print(" "); if (displayWrap > (summary * 10)) {
      Serial.println(logZ);
      displayWrap = 0;
    }
    else
    {
      Serial.print(logZ);
      Serial.print("   ");
    }
    countWrap = 0;
    logX = 0;
    logY = 0;
    logZ = 0;
  }
}
void StartupLog(int startMoveCounter, int x,int y,int z){
  //we are moving, wrap every 15.
    displayWrap++;
    Serial.print(startMoveCounter);      
    //Serial.print("-");
    //Serial.print(x);
    //Serial.print(" ");
    //Serial.print(y);
    //Serial.print(" ");
    //Serial.print(z);
    //Serial.print(" ");
    if (displayWrap > 15) {
      Serial.println(" ");      
      displayWrap = 0;
    }
    else {
      Serial.print(" ");
    }
}

Custom parts and enclosures

Completed Build
The completed device installed in a case
Wmc open yi0pl2axqy

Schematics

Wire connections
Wii nunchuck supplies both motion detection and hookup for buttons.
Circuit testing 2ruonwjjg7

Comments

Similar projects you might like

Weather forecast station with LYT led bulb and IFTTT

Project tutorial by Team Authometion

  • 4,166 views
  • 0 comments
  • 2 respects

Thirst Alert Plant Alarm

Project tutorial by Patchr

  • 9,045 views
  • 5 comments
  • 44 respects

IoT Gauge with Arduino, Yaler & IFTTT

Project tutorial by Thomas Amberg

  • 8,168 views
  • 8 comments
  • 28 respects

Connecting Anduino to IFTTT

Project tutorial by Brian Carbonette

  • 37,385 views
  • 0 comments
  • 15 respects

Intrusion Alert System using Arduino and Bolt IoT

Project tutorial by Rohit Kumar

  • 4,440 views
  • 0 comments
  • 18 respects

Using IFTTT with BLynk

by Kaustubh Agarwal

  • 12,466 views
  • 6 comments
  • 34 respects
Add projectSign up / Login