Laundry Tracker

A project log for Sci-fi grade Home Automation

A system that ties some home automation with various APIs and hardware hacks.

conradcnconradcn 02/27/2015 at 03:430 Comments

After I accidentally left my laundry to rot in the washing machine one too many times, I decided to permanently fix the problem with a Spark Core. I rigged it to cheap door sensors ( on the washer and dryer doors, and used some simple code to figure out which one is being loaded at any given time.

The code for the core is at the end of this post (it's so short, I'm not even sure I'm adding it to the GitHub). I'm not sharing the server-side code because practically the entire thing is access tokens, and I don't want to bother sanitizing it. Spark provides a pretty dead-simple JSON api though, so it shouldn't be hard to work out how the thing translates the variables into something usable as an email.

Things to note:

Those sensors are incredibly delicate. They're essentially just two almost-touching wires and a magnet to pull them together. If you touch them, prepare to spend the next half-hour or so re-calibrating them. That's also why the code has different conditions for the two sensors (they give completely different readings, almost like completely distinct models of sensors). I recommend polling each sensor a few dozen times in each state to figure out what its readings will be.

The sensors are compatible with the 5V output of the core, which stops you from having to worry about the internal batteries. I de-soldered the speaker and replaced it with a wire between the signal pin (the one going to the blob IC in the center of the board) and the core. I removed the can-looking thing (oscillator?) that was between the PCB and the speaker, as it made the signal harder to read from the core.


int washerDoor = 0;
int dryerDoor = 0;
int washerFull = 0;
int dryerFull = 0;
int washerLastClosed = 0;
int dryerLastClosed = 0;
int washerLastOpen = 0;
int dryerLastOpen = 0;
int washerOpenTime = 0;
int dryerOpenTime = 0;

//This is for the washer sensor, which isn't as reliable
int consecutive2k = 0;

void setup() {
    Spark.variable("washerDoor", &washerDoor, INT);
    Spark.variable("dryerDoor", &dryerDoor, INT);
    Spark.variable("washerFull", &washerFull, INT);
    Spark.variable("dryerFull", &dryerFull, INT);
    Spark.variable("washerLast", &washerLastOpen, INT);
    Spark.variable("dryerLast", &dryerLastOpen, INT);
    pinMode(A1, INPUT_PULLUP);
    pinMode(A2, INPUT_PULLUP);

void loop() {
    int t =;
    //Update open/close variables
    //This sensor seems to report a high incidence of zeroes if and only if it is closed, so that's what this checks for
    if(analogRead(A1) > 2000)
        if(consecutive2k > 5)
            washerLastClosed = t;
            washerDoor = analogRead(A1);
    //This sensor reports a value of 2500(ish) if closed, and 3500(ish) if open, so that's what this checks for. Your calibrations may (and likely will) vary significantly
    if(analogRead(A0) < 3000)
        dryerLastClosed = t;
        dryerDoor = 0;
    if(washerLastClosed < (t-2))
        washerDoor = 1;
        washerOpenTime = (t-washerLastClosed);
        washerDoor = 0;
        washerOpenTime = 0;
    if(dryerLastClosed < (t-2))
        dryerDoor = 1;
        dryerOpenTime = (t-dryerLastClosed);
        dryerDoor = 0;
        dryerOpenTime = 0;
    //Do some logic on the results
    //The time requirement means that momentary opening and closing won't change anything, and the time between opening the machines for transfer is negated
    //If the washer door and dryer door are both open, that means that the washer is being loaded into the dryer
    if(washerOpenTime > 10 && dryerOpenTime > 10)
        dryerLastOpen = t;
        dryerFull = 1;
        washerFull = 0;
    //If only the washer door is open, that means that it's being loaded
    if(washerOpenTime > 30 && dryerDoor == 0)
        washerFull = 1;
        washerLastOpen = t;
    //If only the dryer door is open, that means it's being unloaded
    if(dryerOpenTime > 30 && washerDoor == 0)
        dryerFull = 0;