element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Forget Me Not Design Challenge
  • Challenges & Projects
  • Design Challenges
  • Forget Me Not Design Challenge
  • More
  • Cancel
Forget Me Not Design Challenge
Blog Laundry Room Sensor Prototype
  • Blog
  • Forum
  • Documents
  • Files
  • Events
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: electronichamsters
  • Date Created: 4 Oct 2014 12:13 AM Date Created
  • Views 1118 views
  • Likes 0 likes
  • Comments 1 comment
  • forget_me_not
  • flexible_home
Related
Recommended

Laundry Room Sensor Prototype

electronichamsters
electronichamsters
4 Oct 2014
  1. [INDEX]
  2. Introduction and project description
  3. Sensor Node and Gateway Design
  4. How I use OpenHAB - audio notification and dashboards
  5. Design detail for wireless sensor nodes and gateway
  6. Uber Sensor - wireless sensor for fire, smoke, gas, barking, light, movement
  7. Diaper Box Sensor
  8. Laundry Room Sensor

 

I have my laundry room in the basement.  I wanted to make a sensor that will tell me if the laundry is complete, and keep track of whether it's been picked up.  I also wanted a water leak sensor in case something overflows.  This laundry room sensor has the following elements.  Check out the video demo at the very bottom.

 

  • Sound sensor to detect Washer or Dryer running / idle state
  • PIR sensor to detect laundry pickup
  • Light sensor to detect laundry room light
  • Water detection circuit to alarm if something overflows or floods.

 

It looks like this.

image

image

 

 

image

 

The idea is to move the audio notification from the basement to somewhere more optimal - like the living room or kitchen.  Things like a water leak would of course merit an email notification.  Status is displayed on the smart phone.  I'm also keeping track of whether the laundry gets picked up.  I only have one sound sensor right now, but eventually I'd like to equip both the washer and the dryer.

image

 

image

 

Demo Video:

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

 

First, here's the item definition.  I'm defining both MQTT and display-only items to facilitate using rules to massage the graphics.

 

//---------------------------------------
//Item Definition
//---------------------------------------
/*Laundry Room */
//in the <OpenHAB15\webapps\images> folder
//create 3 pngs
// myalarm.png
// myalarm-off.png
// myalarm-on.png
// mylight.png
// myalarm-0.png
// myalarm-1.png
Number itm_laun_dryer_mqtt "Dryer [MAP(laundry.map):%s]" (ALL) {mqtt="<[mymosquitto:3052:state:default]"}
Number itm_laun_washer_mqtt "Washer [MAP(laundry.map):%s]" (ALL) {mqtt="<[mymosquitto:3042:state:default]"}
Switch itm_laun_water_leak_alm_enb "Laundry Water Leak Notifier"
Switch itm_laun_water_leak_alm_sta "Laundry Water Leak Status" <myalarm>
Number itm_laun_water_leak_mqtt "Water Leak" (ALL) {mqtt="<[mymosquitto:3032:state:default]"}
Number itm_laun_temp "Laundry Room Temp [%.1f °F]" <temperature> (All) {mqtt="<[mymosquitto:3022:state:default]"}
Number itm_laun_hum "Laundry Room Humidity [%.1f %%]" <temperature> (All) {mqtt="<[mymosquitto:3023:state:default]"}
Number itm_laun_light_mqtt "Light Sensor [%.1f]" (ALL) {mqtt="<[mymosquitto:3062:state:default]"}
Number itm_laun_light_icon "Laundry Room Light" <mylight>

 

 

Next, I define the colors for the various status of the washer/dryer on the sitemap.

 

Text label="Laundry Room" icon="firstfloor" {
     Frame label="Laundry Room Status"
     {
          Text item=itm_laun_dryer_mqtt valuecolor=[<1="gray",==1="green",>1="red"] labelcolor=[<1="gray",==1="green",>1="red"]
          Text item=itm_laun_washer_mqtt valuecolor=[<1="gray",==1="green",>1="red"] labelcolor=[<1="gray",==1="green",>1="red"]
          Text item=itm_laun_temp
          Text item=itm_laun_hum
          Text item=itm_laun_light_icon
          Switch item=itm_laun_water_leak_alm_sta mappings=[OFF="Reset"]
       }

     Frame label="Alarm Enable"
     {
          Switch item=itm_laun_water_leak_alm_enb
     }
}

 

 

Then I use the rules to define some of graphical states and when to play audio.

 

//---------------------------------------
//Rules
//---------------------------------------
rule "Laundry Lights"
  when
  Item itm_laun_light_mqtt received update
  then
  if(itm_laun_light_mqtt.state < 350)
  {
  sendCommand(itm_laun_light_icon, 0)
  }
  else
  {
  sendCommand(itm_laun_light_icon, 1)
  }
end

rule "Washer Complete"
  when
  Item itm_laun_washer_mqtt received update
  then
  if(itm_laun_washer_mqtt.state == 2)
  {
  say("Washer Complete!")
  }
end
rule "Dryer Complete"
  when
  Item itm_laun_dryer_mqtt received update
  then
  if(itm_laun_dryer_mqtt.state == 2)
  {
  say("Dryer Complete!")
  }
end

/* --------- Laundry Water Leak ---------- */
rule "Laundry Water Leak"
  when
  Item itm_laun_water_leak_mqtt received update
  then
  sendCommand(itm_laun_water_leak_alm_sta, ON)

end

rule "Laundry Water Leak response"
  when
  Item itm_laun_water_leak_alm_sta changed from OFF to ON
  then
  if(itm_laun_water_leak_alm_enb.state == ON)
  {
  sendMail("ArduinoHomeAutomationOpenHAB@gmail.com", "laundry water leak" , "laundry water leak detected")
  }
  //playSound("alarm.mp3")
end

 

The sketch does some counting to figure out if the washer or dryer is running.  The counts would have to be massaged based on how loud your machine is or how sensitive you turn the sound pot.

 

/*
Author: Eric Tsai
License: CC-BY-SA, https://creativecommons.org/licenses/by-sa/2.0/
File: Laundry_room.ino
This sketch is for a wired Arduino w/ RFM69 wireless transceiver
Monitors dryer status, uses PIR sensor to indicate empty load.
Notification for water leaks.
Light sensor.
to gateway. See OpenHAB configuration below.

1) Update encryption string "ENCRYPTKEY"
2)
*/

/*
OpenHAB configuration

Item Definition
Number itm_dryer "Dryer is [MAP(laundry.map):%s]" (ALL) {mqtt="<[mymosquitto:3052:state:default]"}

Sitemap Definition
Text item=itm_dryer valuecolor=[<1="black",==1="green",>1="orange"] labelcolor=[2="orange", 1="green", 0="black"]


Create a file <laundry.map> in /configuration/transform
0=Off & Empty
1=Running
2=Done

Reference
https://github.com/openhab/openhab/wiki/Explanation-of-Items


*/

/* MQTT topic addressing
node = 30

device ID:
2 = 3022 = Temperature_F
  = 3023 = Humidity
3 = 3021 = Water Present
4 = 3042 = Washer status (not implemented)
5 = 3052 = Dryer status (implemented)
6 = 3062 = Light

Pins
A2 = light sensor
3 = water leak
5 = PIR sensor
6 = sound 1
7 = DHT11 sensor
8 = sound 2


*/

//RFM69 --------------------------------------------------------------------------------------------------
#include <RFM69.h>
#include <SPI.h>
#define NODEID 30 //unique for each node on same network
#define NETWORKID 101 //the same on all nodes that talk to each other
#define GATEWAYID 1
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
//#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
#define FREQUENCY RF69_915MHZ
#define ENCRYPTKEY "xxxxxxxxxxxxxxxx" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ACK_TIME 30 // max # of ms to wait for an ack
#define LED 9 // Moteinos have LEDs on D9
#define SERIAL_BAUD 9600 //must be 9600 for GPS, use whatever if no GPS
boolean debug = 0;
//struct for wireless data transmission
typedef struct {
  int nodeID; //node ID (1xx, 2xx, 3xx); 1xx = basement, 2xx = main floor, 3xx = outside
  int deviceID;    //sensor ID (2, 3, 4, 5)
  unsigned long var1_usl; //uptime in ms
  float var2_float; //sensor data?
  float var3_float;    //battery condition?
} Payload;
Payload theData;
char buff[20];
byte sendSize=0;
boolean requestACK = false;
RFM69 radio;
//end RFM69 ------------------------------------------

/*
// gas sensor================================================
int GasSmokeAnalogPin = 0; // potentiometer wiper (middle terminal) connected to analog pin
int gas_sensor = -500; // gas sensor value, current
int gas_sensor_previous = -500; //sensor value previously sent via RFM
*/

//temperature / humidity =====================================
#include "DHT.h"
#define DHTPIN 7 // digital pin we're connected to
#define DHTTYPE DHT11 // DHT 22 (AM2302) blue one
//#define DHTTYPE DHT21 // DHT 21 (AM2301) white one
// Initialize DHT sensor for normal 16mhz Arduino
DHT dht(DHTPIN, DHTTYPE);


// Light sensor ===============================================
int lightAnalogInput = A2; //analog input for photo resistor
int lightValue = -50;
int lightValue_previous = -50;

// PIR sensor ================================================
// used to clear a completed load (to know that it's been emptied)
int PirInput = 5;
int PIR_status = 0;
int PIR_reading = 0;
int PIR_reading_previous = 0;

// sound sensor 1 (Dryer) ==============================================
int soundInput1 = 6; //sound sensor digital input pin
int sound_status1 = 0;
int sound_reading1 = 0; //reading =1 mean no noise, 0=noise
int sound_reading1_previous = 0;
int sound_1_device_state = 0;  //1 = running, 0 = empty, 2 = complete

unsigned long sound_time_1 = 0;   //millis of last reading
int sound_count_1 = 0;   //number of captures
int sound_detected_count_1 = 0; //number of readings showing sound


// water leak sensor ==========================================
unsigned long water_time;
int waterInput = 3;   //pin for water detection
int water_reading = 0;  //for reading water pin


// timings
unsigned long pir_time;
unsigned long sound_time;
unsigned long temperature_time;
unsigned long light_time;
unsigned long light_time_send;


void setup()
{
  Serial.begin(9600); // setup serial
  //RFM69-------------------------------------------
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  #ifdef IS_RFM69HW
  radio.setHighPower(); //uncomment only for RFM69HW!
  #endif
  radio.encrypt(ENCRYPTKEY);
  char buff[50];
  sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
  Serial.println(buff);
  theData.nodeID = NODEID; //this node id should be the same for all devices in this node
  //end RFM--------------------------------------------


  dht.begin();  //temperature & humidity sensor

  pinMode(soundInput1, INPUT);  //sound sensor 1 (dryer)

  pinMode(waterInput, INPUT);    //water detection

  //initialize times
  sound_time = millis();
  temperature_time = millis();
  pinMode(PirInput, INPUT);  //PIR sensor
}
void loop()
{
  unsigned long time_passed = 0;




  //===============================================================
  //Water Leak sensor
  //Device #3
  //===============================================================
  water_reading = digitalRead(waterInput);    //0 = no water, 1 = water (backwards)
  //if (water_reading)
  //Serial.println("no water");
  //else
  //Serial.println("water det ");
  //delay(1000);

  if ((water_reading == 0) && ( ((millis() - water_time)>60000)||( (millis() - water_time)< 0)) ) //meaning there was sound
  {
    water_time = millis(); //update gas_time_send with when sensor value last transmitted

    theData.deviceID = 3;
    theData.var1_usl = millis();
    theData.var2_float = 1;
    theData.var3_float = 101;    //null value;
    radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
    Serial.print("water detected!!! ");

  }


  //===================================================================
  //device PIR
  //note:  this PIR sensor goes straight to I/O, no pull down resistor.
  // 1 = detected movement
  PIR_reading = digitalRead(PirInput);
// if (PIR_reading == 1)
  //Serial.println("PIR = 1");
  //else
  //Serial.println("PIR = 0");

  // if someone is in the laundry room and washer/dryer is complete (not emptied)
  if ((PIR_reading == 1) && (sound_1_device_state == 2))
  {
    sound_1_device_state = 0;
    theData.deviceID = 5;
    theData.var1_usl = millis();
    theData.var2_float = 0;
    theData.var3_float = 11223;    //null value;
    radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
  }


  //===================================================================
  //device #5
  //Dryer Running Sound Sensor

  //soundValue = analogRead(soundAnalogInput);
  //Serial.print("sound analog = ");
  //Serial.print(soundValue);


  //deal with millis rollover
  if (sound_time_1 > millis())
  {
    sound_time_1 = millis();
  }

  //capture sound as fast as we can.  If there is sound, mark it as so.
  int sound = digitalRead(soundInput1);
  if (sound == 0)
  {
    sound_reading1 = 0;
  }

  //count sound as for real only every 1/2 second.
  if ((millis() - sound_time_1)>500)
  {
    sound_time_1 = millis();    //reset sound_time_1 to wait for next Xms

    //sound_reading1 = digitalRead(soundInput1);  // 1 = no noise, 0 = noise!!

    Serial.print(sound_count_1);
    Serial.print(" out of ");
    Serial.print(sound_detected_count_1);
    Serial.print(" state= ");
    Serial.print(sound_1_device_state);
    if (!sound_reading1)
    Serial.println("   sound detected");
    else
    Serial.println("   no sound detected");


    sound_count_1 = sound_count_1 + 1;          //count how many times we listened
    if (sound_reading1 == 0)                    //count how many times detected sound
    {
      sound_detected_count_1 = sound_detected_count_1 + 1;
    }

    sound_reading1 = 1;        //reset back to no sound (1 = no sound)
  }//end reading every second

  //after X number of sound checks...
  if (sound_count_1 >= 40)
  {
    //sound_count_1 = number of times sensor listened
    //sound_detected_count_1 = number of times heard sound
    //sound_1_device_state:  0=emptied, 1=running, 2=cycle complete (but not emptied)

    // sound_1_device_state = 1 = running
    Serial.print("checking checking evaluating sound");
    if ((sound_detected_count_1 >= 8) && ((sound_1_device_state == 0) || (sound_1_device_state == 2)))  //number of times sensor registered sound
    {
      Serial.println("running!");
      sound_1_device_state = 1;

      theData.deviceID = 5;
      theData.var1_usl = millis();
      theData.var2_float = 1;          //1 = device running
      theData.var3_float = 11223;        //doesn't mean a thing
      radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
    }

    // sound_1_device_state = 2 = Cycle complete (but not emptied)
    else if ((sound_detected_count_1 < 3) && (sound_1_device_state == 1))
    {
      Serial.println("not running!!");
      sound_1_device_state = 2;

      theData.deviceID = 5;
      theData.var1_usl = millis();
      theData.var2_float = 2;
      theData.var3_float = 11223;    //null value;
      radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));

      //reset how often sensor has listened and how many sound events detected
    }
    sound_count_1 = 0;
    sound_detected_count_1 = 0;
  } //end if count_count_1


  //===================================================================
  //device #2
  //temperature / humidity
  time_passed = millis() - temperature_time;
  if (time_passed < 0)
  {
  temperature_time = millis();
  }

  //only report temps/humidity after X seconds
  if (time_passed > 360000)
  {
    float h = dht.readHumidity();
    // Read temperature as Celsius
    float t = dht.readTemperature();
    // Read temperature as Fahrenheit
    float f = dht.readTemperature(true);
    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
    }
    Serial.print("Humidity=");
    Serial.print(h);
    Serial.print(" Temp=");
    Serial.println(f);
    temperature_time = millis();
    //send data
    theData.deviceID = 2;
    theData.var1_usl = millis();
    theData.var2_float = f;
    theData.var3_float = h;
    radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
    delay(1000);
  }


  //===================================================================
  //device #6
  //light
  time_passed = millis() - light_time;
  if (time_passed < 0)
  {
    light_time = millis();
    light_time_send = -70000;
  }
  if (time_passed > 2000) //how often to examine the sensor analog value
  {
    light_time = millis();    //update time when sensor value last read
    lightValue = 0;
    //analog value: Less than 100 is dark. greater than 500 is room lighting
    lightValue = analogRead(lightAnalogInput);
    if ((lightValue < (lightValue_previous - 50)) || ((lightValue > (lightValue_previous + 100)) || (705000 < (millis() - light_time_send))) )
    {
      light_time_send = millis();
      theData.deviceID = 6;
      theData.var1_usl = millis();
      theData.var2_float = lightValue;
      theData.var3_float = lightValue + 20;
      radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData));
      lightValue_previous = lightValue;
      Serial.print("light RFM =");
      Serial.println(lightValue);
    }
    //start debug code
    if (debug)
    {
      Serial.print("light analog = ");
      Serial.println(lightValue);
    }

  }// end if millis time_passed >
}//end loop

  • Sign in to reply
  • DAB
    DAB over 11 years ago

    I might have to make one of your water leak sensors.

     

    I got up the other day to find the kitchen covered with water.

    It seems my wife started filling her cold water container and then got distracted. image

     

    So not only did the kitchen floor get flooded, but the water ran down into the basement.

     

    Sigh!

     

    I did make her clean it all up, but there are just times when you wonder what she was thinking.

     

    DAB

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube