Project in progress
"Alexa: Are My Clothes Dry?"

"Alexa: Are My Clothes Dry?" © GPL3+

With Arduino Yun and an accelerometer, monitor clothes dryer vibration, respond to status inquiries, and alert via SMS when the dryer stops.

  • 3,974 views
  • 6 comments
  • 11 respects

Components and supplies

Apps and online services

About this project

Note (Feb. 24, 2018) - The device has been update to include an Alexa Skill for Dryer Status response to "Are my clothes dry?". See Version 2.0 instructions below.

The laundry room in my townhouse is on the lower floor, and my hearing isn't what it used to be. So, I can't always hear the dryer alarm go off to announce the clothes are dry. Since I also don't like wrinkled clothes, I need to know the moment the dryer stops so I can hang things up.

So, I paired a Arduino Yun with an accelerometer and coded the Arduino to post status to a ThingSpeak channel. I added an Alexa Skill and Lambda function to enable "Alexa: Are my clothes dry?" inquiries that check the ThingSpeak channel dryer status and provide a voice response via Echo.

Lastly, the Arduino code includes integration with Cayenne myDevices to send an SMS alert when the dryer stops vibrating. (This will be updated to also use Alexa voice notifications when that feature becomes available to developers.) The device includes a button for the user to start the monitor (trigger an "on" notification) and an LED to visually indicate when the monitor is actively sensing vibration.

Version 1.0 - Dryer Monitor with SMS alert

(See below for Version 2.0 addition of ThingSpeak and Alexa Skill.)

Step 1.1: Wiring the Accelerometer, Button, and LED

The Memsic 2125 accelerometer has 6 pins:

  • X-axis Out; wired to Yun pin 3
  • Y-axis Out; wired to Yun pin 4
  • Ground for X-axis; wired to Yun GND
  • Ground for Y-Axis; wire to Yun GND
  • +5V; wired to Yun 5V
  • T Out (temperature reading for measurement compensating; not used for this project)

The momentary button and 10K ohm resistor are connected to GND, 5V and Yun pin 2, as shown below.

The indicator LED is inserted directly into Yun pins 13 (anode, the long leg) and GND (cathode). (Note: A 220 ohm resistor can also be added in series with the LED anode to limit wear and tear on the LED.)

Power is supplied to the Yun via USB.

That's it!

Step 1.2: Cayenne myDevices Account

Visit the Cayenne myDevices site to create a free account and obtain an authentication token for the Arduino code.

After creating an account, select Add New... > Device/Widget and select the Arduino microcontroller option...

... and then select the Arduino Yun sketch...

... to obtain a code snippet that includes your authentication token and the correct Cayenne library for Yun:

//#define CAYENNE_DEBUG       // Un-comment to show debug messages
#define CAYENNE_PRINT Serial  // Comment this out to disable prints and save space
#include <CayenneYun.h>
// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = "<your token>";
void setup()
{
	Serial.begin(9600);
	Cayenne.begin(token);
}
void loop()
{
	Cayenne.run();
}

Save this snippet to cut/paste into the Arduino sketch later.

Step 1.3: Arduino IDE prep

Launch the Arduino IDE (instructions to download the IDE are available in Arduino.cc Software section) and select Sketch > Include Library > Manage Libraries... .

Search for "Cayenne" libraries and install Cayenne by myDevices

Step 1.4: Arduino Yun code

The Arduino code has several main components:

a) The Bridge Library needed for Yun

#include <Bridge.h>

b) The Cayenne authentication snippet from Step 2

c) Specify the accelerometer pins and variables

// Adjust these to meet your needs
const int buttonPin = 2;            // pin number of the pushbutton
const int xPin = 3;                 // pin number of the X output of the accelerometer
const int yPin = 4;                 // pin number of the Y output of the accelerometer
const int ledPin = 13;              // pin number of the LED
const int waitTime = .1;             // wait time in minutes
const float sensitivityX = 0.002;   // sensitivity of X axis in percent change
const float sensitivityY = 0.002;   // sensitivity of Y axis in percent change
// Variables:
boolean lastButtonState = LOW;
boolean currentButtonState = LOW;
boolean ledState = LOW;
int counter = 0;
float lastPulseX = 0;
float lastPulseY = 0;

The parameters for waitTime, sensitivityX and sensitivityY can be adjusted in the field to account for variation in the vibration intensity of different equipment.

d) Initialize Yun and Cayenne

void setup() {
 // Initialize serial communications:
 Serial.begin(9600);
 // Initiate Cayenne communications
 Cayenne.begin(token);
// Initialize the pins:
 pinMode(xPin, INPUT);
 pinMode(yPin, INPUT);
 pinMode(buttonPin, INPUT);
 pinMode(ledPin, OUTPUT);
 Bridge.begin();
}

e) Monitor accelerometer output

While the monitor is active, the program will continuously check the accelerometer reading to see if there are changes from previous readings. If no changes are detected, the monitor knows that vibration has stopped.

  // Find the change in the pulse:
  changeX = lastPulseX - pulseX;
  changeY = lastPulseY - pulseY;
  // Calculate the percentage change using absolute values:
  percentX = abs(changeX / lastPulseX);
  percentY = abs(changeY / lastPulseY);
  // If the percentage change is less than the sensitivity (i.e. no movement detected)
  if (percentX < sensitivityX && percentY < sensitivityY)

Step 1.5: Configure the Cayenne Device Dashboard Widget

Back at the Cayenne dashboard, select Add New... > Device/Widget and then select Sensors > Generic > Digital Input. Give your widget a name and select the Yun device from Step 2 above. Choose "Digital" for connectivity, pin D13 and "2 State" (on/off) for the widget.

The dashboard widget will indicate the state of the Dryer: green = "on" (sensing vibration) or no-color = "off".

Step 1.6: Configure the Cayenne Device Trigger(s)

Still at the Cayenne dashboard, select Add New... > Trigger. Give your new trigger a name and select the Yun device. Configure as shown below and specify your mobile phone number for the text message. (Alternately, you can specify an email address, or both.)

Tip: If you share the dryer with other people in the household, you can set up an additional trigger to alert everyone when the dryer starts, so they know it's currently in use.

Other Resources:

  • Arduino.cc has a good tutorial on setting up the Yun and connecting to wifi.
  • Cayenne has detailed documentation about configuring the platform for Arduino devices.

{Note (02/24/2018): Cayenne has recently change the Arduino API to require MQTT. The code for this project will need to be updated to use the CayenneMQTT library.}

Version 2.0 - Add Dryer Status check via Alexa Skill + ThingSpeak

Step 2.1: Set up the ThingSpeak Channel

In the Arduino IDE, add the ThingSpeak library via Library Manager:

Next, create a ThingSpeak account (if you don't already have one) and follow the simple instructions for creating a public channel:

After completing the channel set up, make note of your Channel ID and your Write API Key. In your Arduino code, add the following lines and replace the placeholder with your Channel ID and Write API Key.

// ThingSpeak - Version: Latest 
#include <ThingSpeak.h>

// ThingSpeak example
#include "YunClient.h"
YunClient client;

unsigned long myChannelNumber = #######;
const char * myWriteAPIKey = "XXXXXXXXXXXXXXXXXXX";

In the initial setup section, add the following:

void setup() {
 // ThingSpeak
 ThingSpeak.begin(client);
}

And in the main loop add:

     ThingSpeak.setField(1, ledState);
     ThingSpeak.setField(2, percentX);
     ThingSpeak.setField(3, percentY);

     // Write the fields all at once.
     ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
     delay(20000); // ThingSpeak will only accept updates every 15 seconds.  

When the device is activated, the ThingSpeak channel will now show dryer status information in the visualization area.

Step 2.2: Set up the Dryer Alert Alexa Skill

The Dryer Alert requires configuration of the Alexa Skill along with coding of the AWS Lambda function. We'll start with the Alexa Skill.

If you don't already have an Amazon developer account, go to the Alexa Skills Kit (ASK) site and register. There are also some great tutorials available on the site for the basics of creating an Alexa Skill. For the Dryer Alert Skill, you'll need a few basic intents:

{
 "intents": [
   {
     "intent": "DryerStatusIntent"
   },
   {
     "intent": "AMAZON.HelpIntent"
   },
   {
     "intent": "AMAZON.CancelIntent"
   }, 
   {
     "intent": "AMAZON.StopIntent"
   }
 ]
}

You'll also need to specify a few utterances to trigger the AWS Lambda service:

DryerStatusIntent are my clothes dry
DryerStatusIntent check the dryer status
DryerStatusIntent what's the dryer status
DryerStatusIntent what is the dryer status
DryerStatusIntent is the dryer on
DryerStatusIntent is the dryer busy

Follow the ASK tutorials to complete the skill configuration. Make note of the Application ID; you'll need this for the AWS Lambda function setup.

Step 3: Configure the AWS Lambda Function for Dryer Status

Once the Skill configuration is complete, go to the AWS Management Console (create a free account, if needed) and proceed to the Lambda Management Console. Select Create Function:

(If you're new to Lambda, first check out the getting-started tutorial.)

In the Add Triggers section of the Designer, select the Alexa Skills Kit option and use the Application ID from the previous step to connect the Lambda function with the Skill.

The Lambda function Python code is provided in the Code section below. You just need to cut/paste this code into your lambda_function.py. The only thing you'll need to change for this project is to specify your own public ThingSpeak channel and corresponding field you're monitoring.

# Change these elements to point to your data
channel = 177778
field = 1
#

You can also change the voice responses to meet your own needs.

Once the Lambda configuration is complete, make note of the ARN number in the upper right-hand corner and go back to the Skill Configuration page and enter the ARN in the Default end point field. This completes the integration.

If you don't have an Alexa device, you can use the simulation service Echosim.io to give it a whirl.

Future Enhancements:

1) Version 2.1 - When Alexa announces developer support for notifications, add notification for Alexa to alert when the dryer stops: Alexa, "Your clothes are dry".

Code

Version 1.0: Dryer Alert Arduino Code using Cayenne API to send SMS Arduino
The code monitors dryer vibration and uses Cayenne to send SMS when the dryer vibration stops.
// Include statements:
#include <Bridge.h>

//#define CAYENNE_DEBUG       // Uncomment to show debug messages
#define CAYENNE_PRINT Serial  // Comment this out to disable prints and save space
#include <CayenneYun.h>

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = "xxxxxxxxxxxxx";

// Adjust these to meet your needs
const int buttonPin = 2;            // pin number of the pushbutton
const int xPin = 3;                 // pin number of the X output of the accelerometer
const int yPin = 4;                 // pin number of the Y output of the accelerometer
const int ledPin = 13;              // pin number of the LED
const int waitTime = .1;            // wait time in minutes
const float sensitivityX = 0.002;   // sensitivity of X axis in percent change
const float sensitivityY = 0.002;   // sensitivity of Y axis in percent change

// Variables:
boolean lastButtonState = LOW;
boolean currentButtonState = LOW;
boolean ledState = LOW;
int counter = 0;
float lastPulseX = 0;
float lastPulseY = 0;

// Variables to contain the resulting accelerations
  int accelerationX, accelerationY;

// Initial setup
void setup() {
  // Initialize serial communications:
  Serial.begin(9600);
  
  // Initiate Cayenne communications
  Cayenne.begin(token);
  
  // Initialize the pins:
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  
  Bridge.begin();
}

// Debounce function for the pushbutton
boolean debounce(boolean last)
{
  boolean current = digitalRead(buttonPin);
  if(last != current)
  {
    delay(5);
    current = digitalRead(buttonPin);
  }
  return current;
}

// Main loop
void loop()
{
  Cayenne.run();
  delay (5);
     
  // Set the LED
  currentButtonState = debounce(lastButtonState);
  if(lastButtonState == LOW && currentButtonState == HIGH)
  {
    ledState = !ledState;
  }
  lastButtonState = currentButtonState;
  digitalWrite(ledPin, ledState);
  
  // If the led is on
  if (ledState == HIGH)
  { 
    // If the counter is less than the wait time.
    // I multiplied the waitTime by 3000 to account for timing.
    // You may need to adjust this value to get more accurate timing.
    // if (counter < (waitTime * 3000))
    if (counter < (10))  // For testing only
    {
     
      // Declare variables to read the pulse widths, change, and percentage change:
      float pulseX, pulseY, changeX, changeY, percentX, percentY;
    
      // Read pulse from x- and y-axes:
      pulseX = pulseIn(xPin,HIGH);  
      pulseY = pulseIn(yPin,HIGH);
      
      // Convert the pulse width into acceleration
      // accelerationX and accelerationY are in milli-g's:
      // Earth's gravity is 1000 milli-g's, or 1g.
      accelerationX = abs((pulseX / 10) - 500) * 8;
      accelerationY = abs((pulseY / 10) - 500) * 8;
      // print the acceleration
      Serial.print(accelerationX);
      // print a tab character:
      Serial.print("\t");
      Serial.print(accelerationY);
      Serial.println();    
          
      // Find the change in the pulse:
      changeX = lastPulseX - pulseX;
      changeY = lastPulseY - pulseY;
    
      // Calculate the percentage change using absolute values:
      percentX = abs(changeX / lastPulseX);
      percentY = abs(changeY / lastPulseY);
    
      // If the percentage change is less than the sensitivity (i.e. no movement detected)
      if (percentX < sensitivityX && percentY < sensitivityY)
      {      
        // Increase the counter
        counter++;
      }
      // Else if movement is detected
      else
      { 
        // Reset the counter
        counter = 0;
      }

      // Print the counter
      Serial.print(counter);
      Serial.println(); 
      delay(1000);
          
      // Set the last pulse equal to the current pulse
      lastPulseX = pulseX;
      lastPulseY = pulseY;
    }
    else
    {
      // Reset the counter
      // Comment out to end the loop
      counter = 0;
      ledState = LOW;
    }
    //  Serial.print("Life is good.");
    //  Serial.println(); 
    // Serial.end();
    //ledState = LOW;
  }
}
Version 2.0 Update - Add ThingSpeak API configurationArduino
This version adds the necessary library and code to allow monitoring of dryer status via a public ThingSpeak channel.
// ThingSpeak - Version: Latest 
#include <ThingSpeak.h>

// Include statements:
#include <Bridge.h>

//#define CAYENNE_DEBUG         // Uncomment to show debug messages
#define CAYENNE_PRINT Serial  // Comment this out to disable prints and save space
#include <CayenneYun.h>

// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = "u19xjr2vmj";

// ThingSpeak example
#include "YunClient.h"
YunClient client;

unsigned long myChannelNumber = 177778;
const char * myWriteAPIKey = "FCWFJPEHWXSS26U7";

// Adjust these to meet your needs
const int buttonPin = 2;            // pin number of the pushbutton
const int xPin = 3;                 // pin number of the X output of the accelerometer
const int yPin = 4;                 // pin number of the Y output of the accelerometer
const int ledPin = 13;              // pin number of the LED
const int waitTime = .1;             // wait time in minutes
const float sensitivityX = 0.002;   // sensitivity of X axis in percent change
const float sensitivityY = 0.002;   // sensitivity of Y axis in percent change

// Variables:
boolean lastButtonState = LOW;
boolean currentButtonState = LOW;
boolean ledState = LOW;
int counter = 0;
float lastPulseX = 0;
float lastPulseY = 0;

// (TN) variables to contain the resulting accelerations
int accelerationX, accelerationY;


// Initial setup
void setup() {
  // (TN) initialize serial communications:
  Serial.begin(9600);
  
  // (TN) Initiate Cayenne communications
  Cayenne.begin(token);

  // initialize the pins:
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  
  Bridge.begin();

  // ThingSpeak
  ThingSpeak.begin(client);

}

// Debounce function for the pushbutton
boolean debounce(boolean last)
{
  boolean current = digitalRead(buttonPin);
  if(last != current)
  {
    delay(5);
    current = digitalRead(buttonPin);
  }
  return current;
}

// Main loop
void loop()
{
  Cayenne.run();
  delay (5);
     
  // Set the LED
  currentButtonState = debounce(lastButtonState);
  if(lastButtonState == LOW && currentButtonState == HIGH)
  {
    ledState = !ledState;
  }
  lastButtonState = currentButtonState;
  digitalWrite(ledPin, ledState);
  
  // If the led is on
  if (ledState == HIGH)
  { 
    // If the counter is less than the wait time.
    // I multiplied the waitTime by 3000 to account for timing.
    // You may need to adjust this value to get more accurate timing.
    // if (counter < (waitTime * 3000))
    if (counter < (3))  // For testing only
    {
 
      // Declare variables to read the pulse widths, change, and percentage change:
      float pulseX, pulseY, changeX, changeY, percentX, percentY;

      // Read pulse from x- and y-axes:
      pulseX = pulseIn(xPin,HIGH);  
      pulseY = pulseIn(yPin,HIGH);
      
      // [TN] convert the pulse width into acceleration
      // accelerationX and accelerationY are in milli-g's:
      // earth's gravity is 1000 milli-g's, or 1g.
      accelerationX = abs((pulseX / 10) - 500) * 8;
      accelerationY = abs((pulseY / 10) - 500) * 8;
 
      // print the acceleration
      // Serial.print(accelerationX);
      // print a tab character:
      // Serial.print("\t");
      // Serial.print(accelerationY);
      // Serial.println();   
          
      // Find the change in the pulse:
      changeX = lastPulseX - pulseX;
      changeY = lastPulseY - pulseY;
    
      // Calculate the percentage change using absolute values:
      percentX = abs(changeX / lastPulseX) * 100;
      percentY = abs(changeY / lastPulseY) * 100;

      // print the percent change
      Serial.print(percentX);
      // print a tab character:
      Serial.print("\t");
      Serial.print(percentY);
      Serial.println();   
        
      ThingSpeak.setField(1, ledState);
      ThingSpeak.setField(2, percentX);
      ThingSpeak.setField(3, percentY);

      // Write the fields all at once.
      ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
      delay(20000); // ThingSpeak will only accept updates every 15 seconds.  
         
      // If the percentage change is less than the sensitivity (i.e. no movement detected)
      if ((percentX / 100) < sensitivityX && (percentY /100) < sensitivityY)
      {      
        // Increase the counter
        counter++;
      }
      // Else if movement is detected
      else
      { 
        // Reset the counter
        counter = 0;
      }

      // [TN] print the counter
      Serial.print(counter);
      Serial.println(); 
      delay(1000);
          
      // Set the last pulse equal to the current pulse
      lastPulseX = pulseX;
      lastPulseY = pulseY;
    }
    else
    {
      // Reset the counter
      // [TN] Comment out to end the loop
      counter = 0;
      ledState = LOW;
      ThingSpeak.writeField(myChannelNumber, 1, ledState, myWriteAPIKey);      
    }
    //  Serial.print("Life is good.");
    //  Serial.println(); 
    // Serial.end();
    //ledState = LOW;
  }
}
Dryer Status Skill IntentsJSON
Basic intents for configuring the Alexa Skill
{
 "intents": [
   {
     "intent": "DryerStatusIntent"
   },
   {
     "intent": "AMAZON.HelpIntent"
   },
   {
     "intent": "AMAZON.CancelIntent"
   }, 
   {
     "intent": "AMAZON.StopIntent"
   }
 ]
}
Dryer Status Skill Utterancessnippets
Utterances are needed for the Dryer Status intent to trigger the AWS Lambda service
DryerStatusIntent are my clothes dry
DryerStatusIntent check the dryer status
DryerStatusIntent what's the dryer status
DryerStatusIntent what is the dryer status
DryerStatusIntent is the dryer on
DryerStatusIntent is the dryer busy
myDryerStatus Lamdba FunctionPython
The Lambda function instructs Alexa how to interpret utterances from the Dryer Alert skill, how to check dryer status on ThingSpeak, and how to provide voice response based on dryer status.
"""
This skill returns data from a ThingSpeak channel.  In my case, we're checking the status of my dryer.

Ask Alexa "are my clothes dry" to get the current status.

February 2018

Shout out and full credit to kayakpete
https://www.hackster.io/kayakpete/amazon-echo-alexa-thingspeak-data-checker-8677c0

"""

from __future__ import print_function
import urllib

# Change these elements to point to your data
channel = 177778
field = 1
#

link = "https://api.thingspeak.com/channels/" + \
    str(channel) + \
    "/fields/" + \
    str(field) + \
    "/last"

def lambda_handler(event, context):
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])


def on_session_started(session_started_request, session):
    """ Called when the session starts """

    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    """ Called when the user launches the skill without specifying what they
    want
    """

    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Dispatch to your skill's launch
    return get_welcome_response()


def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    # Dispatch to your skill's intent handlers
    if intent_name == "DryerStatusIntent":
        return check_dryer_status(intent, session, link)
    elif intent_name == "AMAZON.HelpIntent":
        return get_welcome_response()
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")


def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.

    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])

# --------------- Functions that control the skill's behavior ------------------

def get_welcome_response():

    session_attributes = {}
    card_title = "Welcome"
    speech_output = "Welcome to Dryer Alert. " \
                    "I can tell you the status of the dryer from Thing Speak. " \
                    "Just ask me to check the dryer status"
    # If the user either does not reply to the welcome message or says something
    # that is not understood, they will be prompted again with this text.
    reprompt_text = "Ask me, what is my dryer status. "
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))

def handle_session_end_request():
    card_title = "Session Ended"
    speech_output = "I hope the current status suits your needs. " \
                    "Party on, dude! "
    # Setting this to true ends the session and exits the skill.
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))

# Check the Dryer Status
def check_dryer_status(intent, session, link):
    session_attributes = {}
    reprompt_text = None
    should_end_session = False
    
    f = urllib.urlopen(link) # Get your data
    result = f.read()
    
    speech_output = "The current dryer status is " + \
                    result + \
                    "."
                    
    ## Comment on the awesomeness
    if result == "1":
        comment = " The dryer is still on, dude."
    else:
        comment = " The dryer is off, dude."
       
    speech_output = speech_output + comment
    
    return build_response(session_attributes, build_speechlet_response(
        intent['name'], speech_output, reprompt_text, should_end_session))

# --------------- Helpers that build all of the responses ----------------------

def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': 'SessionSpeechlet - ' + title,
            'content': 'SessionSpeechlet - ' + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }

Schematics

Dryer Alert wiring
Hook up a MEMSIC 2125 accelerometer to Arduino Yun
dryeralert_iXYp1QGHwW.fz

Comments

Similar projects you might like

Hygge Home - Alexa Smart Bath

Project tutorial by J Howard

  • 5,356 views
  • 2 comments
  • 18 respects

Arduino Home Controller Activated by Alexa

Project tutorial by Jose Cruz

  • 2,408 views
  • 6 comments
  • 3 respects

Wise Shower Driven by Alexa Skill

Project in progress by Virgilio Enrique Aray Arteaga

  • 2,194 views
  • 0 comments
  • 3 respects

Smart Pool: Alexa Controlled Pool Manager

Project tutorial by Benjamin Winiarski

  • 1,360 views
  • 2 comments
  • 7 respects

Alexa Smart Power Strip with Temperature

Project tutorial by Muhammad Afzal

  • 1,203 views
  • 0 comments
  • 7 respects

Alexa Based Smart Home Monitoring

Project tutorial by Adithya TG

  • 22,201 views
  • 20 comments
  • 59 respects
Add projectSign up / Login