Project - Receiving SMS notifications from your washing machine


#1

Hi Guys,

Thought Id share with you my first project with Electric IMP. The inspiration and credit for this goes to:
http://alexba.in/blog/2014/01/06/receiving-sms-notifications-from-your-washer/

I was able to order all the parts from adafruit.com (shipped to Australia in only 5 days great service).

I have made some modifications to the code as some tweaking to settings and sms function was not working.
I have left the code for logging to Firebase (as i didn’t test it).

I’m thinking next embed on the agent a webpage for the current status of the washing. There are still a couple of pins spare so i can attach more, any thoughts suggestions welcome.

Code here:

`
// Run on Agent

// Thresholds to adjust for better accuracy
dataThreshold <- 270; // Minimum accelerometer value to count as ON
onThreshold <- 30; // Number of ON samples before machine enters RUNNING state
offThreshold <- 30; // Number of OFF samples before machine enters OFF state

// State variable
running <- false;

// Keep track of counts
onCount <- 0;
offCount <- 0;

// Twilo code for sending SMS
TWILIO_ACCOUNT_SID <- “xxxxxxxxxxxxxxxxxxxxxxxxxx” // your twilio account SID goes here
TWILIO_AUTH_TOKEN <- “xxxxxxxxxxxxxxxxxxxxxxxxxx” // your twilio passkey goes here
TWILIO_FROM_NUMBER <- “+16xxxxxxxx” // your twilio phone number goes here

// Function for sending SMS via Twilio
function send_sms (number, message) {
local twilio_url = format(“https://api.twilio.com/2010-04-01/Accounts/%s/SMS/Messages.json&quot”, TWILIO_ACCOUNT_SID);
local auth = “Basic " + http.base64encode(TWILIO_ACCOUNT_SID+”:"+TWILIO_AUTH_TOKEN);
local body = http.urlencode({From=TWILIO_FROM_NUMBER, To=number, Body=message});
local req = http.post(twilio_url, {Authorization=auth}, body);
local res = req.sendsync();
//server.log(auth);
if(res.statuscode != 201) {
server.log("error sending message: "+res.body);
}
}

// Array of phone numbers to be contacted with the laundry is done
phoneNumbers <- ["+61xxxxxxxxx", “+61xxxxxxxxx”];

// Firebase
logToFirebase <- false;
firebaseURL <- “https://FIREBASE_URL.firebaseIO.com/data.json”;
firebaseHeaders <- { “Content-Type”: “application/json” };

// Called every time the imp emits data
device.on(“data”, function(data) {

// Is there enough accelerometer activity for the device to be considered ON?
if (data >= dataThreshold) {
    onCount = onCount + 1;

    // Prevent overflow errors by resetting onCount when it gets close to limit
    if (onCount >= 65500) {
        onCount = onThreshold;
    }  

    // If the device has been ON for long enough, set running state to be true
    if (onCount >= onThreshold) {
        running = true;

        // Running, so reset offCount
        offCount = 0;
    }

    // debug / logs
    if (running == true) {
        server.log(format("ON - RUNNING (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
    } else {
        server.log(format("ON (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
    }

// Imp is not recording much accelerometer movement, so device seems to be OFF
} else {
    offCount = offCount + 1;

    // Prevent overflow errors by resetting offCount when it gets close to limit
    if (offCount >= 65500) {
        offCount = offThreshold;
    }

    // Has the device been off for long enough to be "done"?
    if (offCount >= offThreshold) {
  
        // Was the device previously running?
        if (running == true) {
            
            // This means that the laundry had been running, and is now done.
            
            // Send an SMS to each phone number in the phoneNumbers array.
            foreach (number in phoneNumbers) {
                send_sms(number, "Candice your washing has finished!")
            }

            // debug / logs
            server.log("!!!! Emitting OFF event !!!!");
        }
      
        // Reset on count
        onCount = 0;
        
        // Machine is no longer running
        running = false;
    }

    // debug / logs
    if (running == true) {
        server.log(format("OFF - WAS RUNNING (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
    } else {
        server.log(format("OFF (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
    }
}

if (logToFirebase == true) {
    // Build a post request to Firebase to log the data
    local body = format("{\"amount\": %f, \"running\": %s, \".priority\": %d}", data, running ? "true" : "false", time());
    local request = http.post(firebaseURL, firebaseHeaders, body);
    
    // Send the data to Firebase async
    local response = request.sendasync(function(done) {});
}

});
`

`
// Run on Device

total <- 0; // Sum of % change from all samples
n <- 0; // Counter for number of samples read
last <- 1; // Previous reading of magnitude

function readSensor() {
// Time interval
local interval = 0.02;

// Get source voltage, should be 3.3V
local vRef = hardware.voltage();

// Read in ADC values from accelerometer
local adcRx = hardware.pin1.read();
local adcRy = hardware.pin2.read();
local adcRz = hardware.pin5.read();
// server.log(format("Raw ADC values: %f, %f, %f", adcRx, adcRy, adcRz));

// Convert 16bit ADC accelerometer values (0-65535) into voltage
local voltsRx = (adcRx * vRef) / 65535.0;
local voltsRy = (adcRy * vRef) / 65535.0;
local voltsRz = (adcRz * vRef) / 65535.0;
// server.log(format("Voltages: %f, %f %f", voltsRx, voltsRy, voltsRz));

// Subtract 0g (1.5V at 3V, 1.65V at 3.3V)
local deltaVoltsRx = voltsRx - (vRef / 2);
local deltaVoltsRy = voltsRy - (vRef / 2);
local deltaVoltsRz = voltsRz - (vRef / 2);
// server.log(format("Adjusted voltages %f, %f, %f", deltaVoltsRx, deltaVoltsRy, deltaVoltsRz));

// Convert from voltage to g, using sensitivity of 300mV
local rX = deltaVoltsRx / 0.3;
local rY = deltaVoltsRy / 0.3;
local rZ = deltaVoltsRz / 0.3;
//server.log(format("Gs: %f, %f, %f", rX, rY, rZ));

// Compute magnitude of force
local magnitude = math.sqrt(math.pow(rX,2) + math.pow(rY, 2) + math.pow(rZ, 2));

// Compute % change since last reading
local change = math.fabs((magnitude - last)/last) * 100.0;

// Store magnitude in last for next time
last = magnitude;

// Log magnitude and percent change
// server.log(format("magnitude: %f, change amount: %f", magnitude, change));

// Increment total with % change, increment N
total = total + change;
n = n + 1;

// Log data to server once ever 250 samples (8 seconds)
// Log data to server once ever 170 samples (5 seconds) new threshold
if (n >= 170) {
    agent.send("data", total);
    n = 0;
    total = 0;
}

// Sleep until time to read sensor again
imp.wakeup(interval, readSensor);

}

// X input
hardware.pin1.configure(ANALOG_IN);

// Y input
hardware.pin2.configure(ANALOG_IN);

// Z input
hardware.pin5.configure(ANALOG_IN);

// Start reading the sensor
readSensor();
`


Variant on old Washing Machine project using LIS2DH12 Accelerometer on impExplorer Dev kit
#2

Very cool project - always glad to see people using other’s shared work!

Let us know how the embedding information on a webpage goes. I recommend using Firebase for that, if you’re already pushing data to it from the agent :slight_smile:


#3

A real serious problem with washers is the broken hoses while you’re not home.
Maybe you can add a water sensor that lays on the floor behind the washer.
It would at least email or text you an alert if you were away. You could call a family member or neighbor to go over and check it out.

Maybe something like this?
http://www.robotmesh.com/grove-water-sensor?gclid=CMO3t6njicECFQctaQodpjsA0w


#4
A real serious problem with washers is the broken hoses while you're not home. Maybe you can add a water sensor that lays on the floor behind the washer.
What a great Idea! Will have to look into that. Thanks for the suggestion.

#5

Does your Twilio function still work? I was setting up my garage door controller to SMS me the door status when it changes and your function doesn’t match Twilio’s documentation for how the URL should be formatted. Plus, your code differs from the code from the project you used as a reference.

Your code:
local twilio_url = format("https://api.twilio.com/2010-04-01/Accounts/%s/SMS/Messages.json

Their code:
twilioURL <- “https://USER:PASS@api.twilio.com/2010-04-01/Accounts/ID/Messages.json”;

Documentation code:
https://api.twilio.com/2010-04-01/Accounts/SID/Messages.json’ \
–data-urlencode ‘To=to-number’ \
–data-urlencode ‘From=twilio-number’ \
–data-urlencode ‘Body=message’ \
-u SID:TOKEN]

Just want to get this right without incurring a bunch of charges testing it. :slight_smile:


#6

I had the same issues with SMS notifications from the original code.
The code in my post above has the sms function which I had to modify.

local twilio_url = format(“https://api.twilio.com/2010-04-01/Accounts/%s/SMS/Messages.json&quot”, TWILIO_ACCOUNT_SID);

This is the url I use and is working (verified on the weekend)


#7

I use the same url as @Buzzcola, works for me.


#8

Good to know. I am currently not using SMS (but want it as a possible option). At the moment, I’m using Mailgun to send emails. The format for sending is almost identical. I use email when it isn’t as pressing that the message gets through.

// Function for sending Email via MailGun
function sendEmailMailGun(subject, message)
{
local from = MAILGUN_FROM_EMAIL;
local to = MAILGUN_TO_EMAIL;
local apikey = MAILGUN_API_KEY;
local domain = MAILGUN_DOMAIN;
local req = http.post(“https://api:” + apikey + "@api.mailgun.net/v2/" + domain + “/messages”, {“Content-Type”: “application/x-www-form-urlencoded”}, “from=” + from + “&to=” + to + “&subject=” + subject + “&text=” + message);
local res = req.sendsync();

//server.log(auth);
if(res.statuscode != 200)
{
    server.log("Error " + res.statuscode + " sending Email message (MailGun): " + res.body );
} else {
    server.log("Sent Email Door State (MailGun): " + a_currentDoorState );
}

}


#9

Hey guys,
I’m trying to add a webpage to the agent to get the latest status of the washing machine ie the “running” state variable so i can use the url to see the current status.
Any help?
thanks Martin


#10

This project is likely a good starting point :slight_smile:

https://github.com/beardedinventor/HackIndicator

It serves up a really simple webpage to indicate the status of a variable.


#11

OOOHH THANK YOU @BUZZCOLA! I was losing my mind figuring out the right approach from Twilios documentation. This clears up a lot!


#12

Its been a while but i just came back to this project to add the web code…
if anyone else is interested just add the below code to the bottom the the agent code

`//Webpage code
washingmachinestate <- “Waiting for device to send state"
if (running == false) {
washingmachinestate = “Not Running”
} else {
washingmachinestate = “Currently Running”
}
function setPage(){
local page = @”

Candices Washing Machine Page

Washing Machine Status

" + washingmachinestate + @"

";

return page;
}

http.onrequest(function(req, resp) {
resp.send(200, setPage());
});`


#13

Sorry all found bug in above code, the washingmachinestate variable wasn’t being updated as it was only run once. I have moved it to the setPage function so the variable get refreshed when the page is loaded. See updated code (tested this time). :slight_smile:

`
//Webpage code
washingmachinestate <- “Waiting for device to send state”

function setPage(){
if (running) {
washingmachinestate = “Currently Running”;
} else {
washingmachinestate = “Not Running”;
}
local page = @"

Washing Machine Status Page

Washing Machine Status

" + washingmachinestate + @"

";

return page;
}

http.onrequest(function(req, resp) {
resp.send(200, setPage());
});
`


#14

Thanks for these updates, I just returned to this project and spent an unsuccessful hour trying to get twilio to work. I will try you code later today (hopefully) and report back .


#15

I have also added if the device is on. See updated code below:

`
//Webpage code
washingmachinestate <- "Waiting for device to send state"
connectedString <- “Device Disconnected”;

//Test if device is running
function setPage(){
if (running) {
washingmachinestate = “Currently Running”;
} else {
washingmachinestate = “Not Running”;
}
//Test if device is connected
if (device.isconnected())
{
connectedString = “Device Connected”;
}
//server.log(connectedString);

local page = @"

Candices Washing Machine Page

Washing Machine Status

" + connectedString + @"

" + washingmachinestate + @"

";

return page;
}

http.onrequest(function(req, resp) {
resp.send(200, setPage());
//server.log(setPage());
});
`


#16

Just idea - I used IFTTT library to send me a sms using the Maker–>Gmail recipe. No charges as long as you can email your self an SMS.


#17

Just as a heads up, I think the last time I played with the SMS channel on IFTTT you could only send about 10 messages a month, even to yourself (though this may have changed).


#18

Hi Guys, I have put the code in like above Sept 2014 post from Buzzcola and I get syntax errors on line 22
local twilio_url = format(“https://api.twilio.com/2010-04-01/Accounts/%s/SMS/Messages.json&quot”, TWILIO_ACCOUNT_SID);

any help would be great


#19

Hey Ericmace, I think when i copied and pasted the code one of the quotes was missing.
try the following line:
local twilio_url = format(“https://api.twilio.com/2010-04-01/Accounts/%s/SMS/Messages.json&quot”, TWILIO_ACCOUNT_SID);

I think the forum code quoting played around the url formatting…


#20

looks like it did it again. I took a screen shot of the code
hope this helps