Shawn hymel
Published © CC0

Jibo Laundry Alert

A new skill for Jibo that alerts you when your laundry is ready. You will also need a Particle Photon and accelerometer.

AdvancedFull instructions provided2 hours298
Jibo Laundry Alert

Things used in this project

Hardware components

Photon
Particle Photon
×1
SparkFun MMA8452Q
×1
SparkFun Photon Battery Shield
×1
Breadboard (generic)
Breadboard (generic)
×1
Male Header 40 Position 1 Row (0.1")
Male Header 40 Position 1 Row (0.1")
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Jibo SDK
Maker service
IFTTT Maker service

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Jibo Laundry Alert Schematic

Block diagram for the Particle Photon and accelerometer.

Code

laundry-done.keys

JSON
Key frames for Jibo's laundry done animation.
No preview (download only).

index.js

JavaScript
Main Jibo SDK code
"use strict";

// Needed to turn Jibo into a web server
let http = require('http');

// Main Jibo library
let jibo = require ('jibo');
let Status = jibo.bt.Status;

// Port number for Jibo's web server
const port = 4242;

jibo.init('face', function(err) {
    if (err) {
        return console.error(err);
    }
    // Load and create the behavior trees
    let root = jibo.bt.create('../behaviors/main');
    root.start();

    // Listen for the jibo main update loop
    jibo.timer.on('update', function(elapsed) {
        // If the tree is in progress, keep updating
        if (root.status === Status.IN_PROGRESS) {
            root.update();
        }
    });

    // Start listening on a port for an HTTP request
    const server = http.createServer()
    server.on('request', (req, res) => {
      res.statusCode = 200;
      console.log(req);

      // Parse the JSON from the request's body
      var body = [];
      req.on('data', function(chunk) {
        body.push(chunk);
      }).on('end', function() {
        body = Buffer.concat(body).toString();
        if (JSON.parse(body).message === 'clothes done') {
          root.emitter.emit('laundry');
        }
      });
    });

    server.listen(port, () => {
      console.log('Server running at http://' + server.address().address + ':' +
        server.address().port);
    });
});

laundry-alarm-ifttt.ino

C/C++
The Particle Photon reads MMA8452Q accelerometer data and publishes a Particle event when the shaking stops.
// This #include statement was automatically added by the Particle IDE. 
#include "SparkFunMMA8452Q/SparkFunMMA8452Q.h" 

enum { 
 NO_SHAKING_LONG, // Haven't been shaking for a long time 
 NO_SHAKING,  // Hasn't been any shaking 
 PRE_SHAKING, // Started shaking, pre-hysteresis 
 SHAKING,     // Currently shaking 
 POST_SHAKING // Stopped shaking, pre-hysteresis 
} shakingState = NO_SHAKING; 

// Possible return values from the shake sensor 
enum sensorShakeReturn { 
 SENSOR_SHAKING, 
 SENSOR_NOT_SHAKING, 
 SENSOR_NOT_READY 
}; 

// Check shake function 
sensorShakeReturn checkShake(void); 

// Shake detection parameters 
unsigned int shakeThreshold = 3; 
unsigned int shakeStartTimeHysteresis = 1000; 
unsigned int shakeStopTimeHysteresis = 10; 
unsigned long shakeStateChangeTime = 0; 
unsigned long shakeStartTime = 0; 
bool loadTimer = true; 

// Global variables 
MMA8452Q accel; 
int16_t lastX, lastY, lastZ; 
void initAccel(void); 
bool notifyFlag = false; 

// Pins 
const int LED_PIN = 7; 

void setup() 
{ 
   // Set up LED 
   pinMode(LED_PIN, OUTPUT); 
   digitalWrite(LED_PIN, LOW); 

   // Set up accelerometer 
   initAccel(); // Set up accelerometer 
} 

void loop() 
{ 
   // Check for shaking 
   sensorShakeReturn sensorState = checkShake(); 

   // If the sensor is shaking 
   if (sensorState == SENSOR_SHAKING) 
   { 
       switch (shakingState) 
       { 
           case NO_SHAKING_LONG: 
           case NO_SHAKING: 

               // No shaking 
               shakingState = PRE_SHAKING; 
               shakeStateChangeTime = millis(); 

               // Start timer if we've started shaking 
               if (loadTimer) 
               { 
                   loadTimer = false; 
                   shakeStartTime = millis(); 
               } 

               break; 

           case PRE_SHAKING: 

               // If we're pre-hysteresis shaking, turn on LED and set state shaking 
               if (millis() - shakeStateChangeTime >= shakeStartTimeHysteresis) 
               { 
                   shakingState = SHAKING; 
                   digitalWrite(LED_PIN, HIGH); 
                   notifyFlag = true; 
               } 

               break; 

           case SHAKING: 

               break; 

           case POST_SHAKING: 

               // If we didn't stop shaking before hysteresis 
               shakingState = SHAKING; 
               break; 
       } 
   } 
   else if (sensorState == SENSOR_NOT_SHAKING) 
   { 
       switch (shakingState) 
       { 
           case NO_SHAKING_LONG: 

               break; 

           case NO_SHAKING: 

               // Check if it's been a long time 
               if (millis() - shakeStateChangeTime >= 
                    (shakeStopTimeHysteresis * 1000)) 
               { 
                   shakingState = NO_SHAKING_LONG; 
                   if (notifyFlag == true) // If notify flag was set during shaking 
                   { 
                       loadTimer = true; 
                       notifyFlag = false; // Clear notify flag 

                       // Washer or dryer is done! Notify IFTTT 
                       Particle.publish("laundry-done"); 
                   } 
               } 

               break; 

           case PRE_SHAKING: 

               // If we're pre-hysteresis shaking, go back to no shaking 
               shakingState = NO_SHAKING; 

               break; 

           case SHAKING: 

               // If we're already shaking, go to hysteresis cooldown 
               shakingState = POST_SHAKING; 
               shakeStateChangeTime = millis(); 

               break; 

           case POST_SHAKING: 

               // If we're in the shake cooldown state, turn off LED 
               if (millis() - shakeStateChangeTime >= shakeStartTimeHysteresis) 
               { 
                   digitalWrite(LED_PIN, LOW); 
                   shakingState = NO_SHAKING; 
               } 

               break;       
       } 
   } 
} 

sensorShakeReturn checkShake(void) 
{ 
   static unsigned long lastShakeCheck = 0; 
   float shake = 0; 

   // If new accelerometer data is available 
   if ( accel.available() ) { 
       int16_t x, y, z; 

       // Sample data from the accelerometer 
       accel.read(); 
       x = accel.x; 
       y = accel.y; 
       z = accel.z; 

       // To determine if we're shaking, compare the sum of 
       // x,y,z accels to the sum of the previous accels. 
       shake = abs(x + y + z - lastX - lastY - lastZ); 

       // Update previous values: 
       lastX = x; 
       lastY = y; 
       lastZ = z; 
   } 
   else 
   { 
       // The sensor did not have new data 
       return SENSOR_NOT_READY; 
   } 

   // If the sensor is "shaking" 
   if (shake >= shakeThreshold) { 
       return SENSOR_SHAKING; 
   } 
   else 
   { 
       return SENSOR_NOT_SHAKING; 
   } 
} 

void initAccel(void) 
{ 
   // Use a slow update rate to throttle the shake sensor. 
   // ODR_6 will set the accelerometer's update rate to 6Hz 
   // Use +/-2g scale -- the lowest -- to get most sensitivity 
   accel.begin(SCALE_2G, ODR_6); // Initialize accelerometer 
   while (!accel.available()) // Wait for data to be available 
   //yield(); // Let the system do other things 
   accel.read(); // Read data from accel 
   lastX = accel.x; // Initialize last values 
   lastY = accel.y; 
   lastZ = accel.z; 
} 

jibo-laundry-done

Repository containing the Jibo code.

Credits

Shawn hymel

Shawn hymel

10 projects • 116 followers
Engineering Superhero at SparkFun Electronics.

Comments