Problem Statement: Our laundry machine is located in the basement and my roommates often have to check multiple times to see when their laundry is done.
Goal: Create a device that notifies my roommates when their laundry is done.
Process:
I decided to use a microphone that would detect the washer/dryer buzzer. An accelerometer seemed like an equally valid option, but we had done a tutorial with the mic on Sunday so I went in that direction.
The code I started with is below, which I took from our Sunday tutorial. You can also see my circuit's early stages.
// the pin we're reading from
int mic_pin = xxx;
// store the noise level / reading from the electret
// TODO: CREATE A INTEGER VARIABLE NAMED noise_level
int xxxxxxx
const int sampleWindow = 50;
// TODO: CREATE A INTEGER VARIABLE NAMED numPins and initialize it to 5
int
int ledPins[ 5 ] = { D0, D1, D2, D3, D4 };
void setup(){
// start serial connection
Serial.begin(9600);
for( int i = 0 ; i < numPins; i++ ){
// TODO: Set the pinmode to output
pinMode(ledPins[ i ], XXXXX);
}
}
void loop()
{
noise_level = sampleNoise( );
// TODO: Write the noise_level to serial
// Hint: Serial.println
displayNoiseOnLEDs();
// TODO: Wait for 50 milliseconds before looping again
XXXXXXX
}
void displayNoiseOnLEDs(){
int level = 200;
for( int i = 0 ; i < numPins; i++ ){
int led = ledPins[ i ];
int desiredLevel = 200 * (i+1);
if( noise_level > desiredLevel ){
// TODO: Write the led to HIGH
}else{
// TODO: Write the led to LOW
}
}
}
int sampleNoise( )
{
unsigned long startMillis = millis(); // Start of sample window
int highest_sample = 0;
int lowest_sample = 1000;
// collect data for 50 mS
while (millis() - startMillis < sampleWindow)
{
int sample = analogRead( mic_pin );
// invert the range, and convert it to a percent
sample = map( sample, 0, 4095, 1000, 0 );
// now see if the sample is the lowest;
if ( sample > highest_sample ){
highest_sample = sample ;
}
if ( sample < lowest_sample ){
lowest_sample = sample;
}
}
int peakToPeak = highest_sample - lowest_sample;
return peakToPeak;
}
Click to Expand
I remixed our Sunday tutorial code to provide a notification when the laundry machine stopped running. To do so, I used an IFTTT applet to send me a push notification whenever the sound crossed a certain threshold. I started with SMS but switched to IFTTT push notifications because I didn't want to go over my SMS limit.
I added a switch and status light so I could know when it was publishing events and turn it off while I debugged.
I also added a "notification" LED that would light whenever the event published. This was mainly helpful when I was debugging and trying to calibrate the sound sensitivity.
// this was my original code for a laundry notification
// the pin we're reading from
int mic_pin = A0;
// store the noise level / reading from the electret
int noise_level = 0;
const int sampleWindow = 50;
int notifyLed = D5;
int switchPin = D1;
int statusLed = D0;
void setup(){
// start serial connection
pinMode(notifyLed, OUTPUT);
pinMode(switchPin, INPUT_PULLUP);
pinMode(statusLed, OUTPUT);
Serial.begin(9600);
// Share the value as a noise level
// reading through the cloud
Particle.variable( "noise", &noise_level, INT );
}
void loop()
{
noise_level = sampleNoise( );
int buttonState = digitalRead( switchPin );
Serial.println( noise_level );
delay( 100 );
if (buttonState == LOW){
digitalWrite(statusLed, LOW);
}
else {
digitalWrite(statusLed, HIGH);
if (noise_level > 5500 ){
Particle.publish("wash_status", "done");
digitalWrite(notifyLed, HIGH);
}
else {
digitalWrite(notifyLed, LOW);
}
}
}
int sampleNoise( )
{
unsigned long startMillis = millis(); // Start of sample window
int highest_sample = 0;
int lowest_sample = 2000;
// collect data for 50 mS
while (millis() - startMillis < sampleWindow)
{
int sample = analogRead( mic_pin );
// invert the range, and convert it to a percent
sample = map( sample, 0, 4095, 6000, 0 );
// now see if the sample is the lowest;
if ( sample > highest_sample ){
highest_sample = sample ;
}
if ( sample < lowest_sample ){
lowest_sample = sample;
}
}
int peakToPeak = highest_sample - lowest_sample;
return peakToPeak;
}
Click to Expand
Unfortunately, on Thursday night, something happened to my microphone and it stopped receiving information. I tried re-soldering but couldn't get it to work.
In the name of improvisation, I switched to a device that would send me a notification whenever it detected motion. It uses the same switch and status light functionality that my original laundry device implemented. I thought this could notify me when my dog breaks into the kitchen.
The code is repurposed from our lab: http://diotlabs.daraghbyrne.me/7-communicating-events/pir/.
int statusLed = D0; // choose the input pin (for PIR sensor)
int notifyLed = D5; // LED Pin
int pirState = LOW;
int switchPin = D1;
int inputPin = D6; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int calibrateTime = 10000; // wait for the thingy to calibrate
void setup()
{
pinMode(switchPin, INPUT_PULLUP);
pinMode(statusLed, OUTPUT);
pinMode(inputPin, INPUT);
pinMode( notifyLed, OUTPUT ); // declare sensor as input
}
void loop()
{
int buttonState = digitalRead( switchPin );
// if the sensor is calibrated
if (buttonState == HIGH)
// starts the function and turns on the light to detect motion
{
digitalWrite(statusLed, HIGH);
if ( calibrated() )
{
// get the data from the sensor
readTheSensor();
// report it out, if the state has changed
reportTheData();
}
}
else {
digitalWrite(statusLed, LOW);
}
}
void readTheSensor() {
val = digitalRead(inputPin);
}
bool calibrated() {
return millis() - calibrateTime > 0;
}
void reportTheData() {
// if the sensor reads high
// or there is now motion
if (val == HIGH) {
// the current state is no motion
// i.e. it's just changed
// announce this change by publishing an event
if (pirState == LOW) {
// this publishes an event for an IFTTT applet
Particle.publish("motion_detector", "done");
// Update the current state
pirState = HIGH;
setLED( pirState );
}
} else {
if (pirState == HIGH) {
// we have just turned of
// Update the current state
pirState = LOW;
setLED( pirState );
}
}
}
void setLED( int state )
{
digitalWrite( notifyLed, state );
}
Click to Expand
Outcome: The laundry device effectively sent push notifications based on a predefined sound threshold. It was a little too sensitive, which needs some additional work.
The improvised motion detector appears to work as intended.
The final video, diagram, and parts are below.
( I'm not sure if this video is showing up. It's below the 20mb threshold, but doesn't seem to be working)
Reflection
To be honest, I was nervous about this project. I have very informal coding experience and no circuit experience, so I wasn't sure how well it'd go.
Fortunately, I found the basics to be pretty accessible, particularly with IFTTT. I was disappointed my mic broke before I could document my laundry hack, but I was happy that I could pull together a new device without too much added work.
I enjoyed getting familiar with the fundamentals and look forward to working on more projects.
This project is only accessible by signed in users. Be considerate and think twice before sharing.
A hands-on introductory course exploring the Internet of Things and connected product experiences.
I want to build a tool that sends my roommates a notification when their laundry is done.
January 26th, 2017