Jose Cruz
Published © GPL3+

Arduino Home Controller Activated by Alexa

With Arduino Home Controller and Amazon Echo dot with Alexa you can handle internet connected devices at home using your voice.

AdvancedFull instructions providedOver 1 day15,167
Arduino Home Controller Activated by Alexa

Things used in this project

Hardware components

Arduino Yun
Arduino Yun
×1
4-CHANNEL RELAY CONTROLLER FOR I2C
ControlEverything.com 4-CHANNEL RELAY CONTROLLER FOR I2C
×1
DHT11 Temperature & Humidity Sensor (4 pins)
DHT11 Temperature & Humidity Sensor (4 pins)
×1
Resistor 10k ohm
Resistor 10k ohm
×2
SparkFun RedBot Buzzer
SparkFun RedBot Buzzer
×1
General Purpose Transistor NPN
General Purpose Transistor NPN
×1
LM2596 DC to DC Buck Converter
×1
Echo Dot
Amazon Alexa Echo Dot
×1
Arduino Proto Shield
×1
Usb WebCam
×1
White Junction Box 200mmx155mmx80mm
×1

Software apps and online services

Arduino IDE
Arduino IDE
Alexa Skills Kit
Amazon Alexa Alexa Skills Kit
AWS Lambda
Amazon Web Services AWS Lambda
PubNub Publish/Subscribe API
PubNub Publish/Subscribe API

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Arduino Yun Home Controller

Main board with reles, temperature and humidity sensor, buzzer alarm and webcam.

Code

ArduinoHomeMQTT.ino

Arduino
Arduino Yun software for Home Controller
//
// ArduinoHomeMQTT
// v2.1
//
// Copyright (C)2018 Jose Cruz. All right reserved
// web: https://sites.google.com/view/raeiot/home
//
#include <YunClient.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <Process.h>

// Your Amazon email linked skill
#define MyID "YOUR AMAZON EMAIL LINKED IN ALEXA APP"

// DHT11 sensor data pin
#define DHTPIN 2
// DHT 11 sensor type
#define DHTTYPE DHT11
// Initialize DHT sensor
DHT dht(DHTPIN, DHTTYPE);

// Alarm control pin
#define alarm 8

// Light control pins
#define room_light 9
#define kitchen_light 10
#define garage_light 11
#define livingroom_light 12

// PubNub MQTT Server address and port
int mqtt_server_port = 1883;
const char* mqtt_server = "mqtt.pndsn.com";
// Suscribe topic
const char* topic = "AHC_IOT_01";
// Publish topic
const char* topic2 = "AHC_IOT_02";

// PubNub publisher ID
//  pub-c-e93def7f-95aa-475a-aa60-cc3cd32ee8a7/
// PubNub suscriber ID
//  sub-c-ec04dbbc-0893-11e8-8e75-cea83f8405bb/
// UUID generated onlyne https://www.uuidgenerator.net/
//  
// PubNub Client ID
//  clientId = pubID + subID + uuid;
const char* clientId = "pub-c-e93def7f-95aa-475a-aa60-cc3cd32ee8a7/sub-c-ec04dbbc-0893-11e8-8e75-cea83f8405bb/YOUR UUID GENERATED";


// Define de Yun ethernet client
YunClient ethClient;
// Define PubNub pub and sub client
PubSubClient client(ethClient);

// Picture process
Process picture;

// Filename
String filename;
// Path for image file
String path = "/mnt/sda1/";

// Create an image file and sent by email
void TakePhoto() {
  // Generate filename with timestamp
  filename = "";
  picture.runShellCommand("date +%s");
  while (picture.running());

  while (picture.available() > 0) {
    char c = picture.read();
    filename += c;
  }
  filename.trim();
  filename += ".jpg";

  // Take picture
  picture.runShellCommand("/usr/bin/fswebcam  -i 0 --jpeg 95 --no-banner --fps 1 -S 1 -r 352x288 --save " + path + filename);
  while (picture.running());

  //Send it by email
  picture.runShellCommand("python /mnt/sda1/AHC_SendEmail.py " + path + " " + filename);
  while (picture.running());
}

//***********************
// Send temperature
//***********************
void SendTemperature()
{
  char cstr[16];
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();

  //  Serial.print("Temperature: ");
  //  Serial.print(t);
  //  Serial.println(" *C");

  client.publish(topic2, itoa(t, cstr, 10));
  //Serial.print("Temperature sent...");
  //Serial.println(cstr);
}

//***********************
// Send humidity
//***********************
void SendHumidity()
{
  char cstr[16];
  float h = dht.readHumidity();
  //Serial.print("Humidity: ");
  //Serial.print((int)h);
  //Serial.print(" %\t");

  client.publish(topic2, itoa(h, cstr, 10));
  //Serial.print("Humidity sent...");
  //Serial.println(cstr);
}

//Callback function for msg receive handle
void callback(char* topic, byte* payload, unsigned int length) {

  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject((char[])payload);

  String alexa_topic  = root["topic"];
  String alexa_command = root["command"];
  String alexa_id = root["id"];

  //Serial.println(alexa_topic);
  //Serial.println(alexa_command);

   if (alexa_id.equals(MyID)) {
    //Handle all received msgs topic from MQTT
    if (alexa_topic.endsWith("Topic_room")) {
      digitalWrite(room_light, (alexa_command.endsWith("on") ? LOW : HIGH));
    } else if (alexa_topic.endsWith("Topic_kitchen")) {
      digitalWrite(kitchen_light, (alexa_command.endsWith("on") ? LOW : HIGH));
    } else if (alexa_topic.endsWith("Topic_garage")) {
      digitalWrite(garage_light, (alexa_command.endsWith("on") ? LOW : HIGH ));
    } else if (alexa_topic.endsWith("Topic_living room")) {
      digitalWrite(livingroom_light, (alexa_command.endsWith("on") ? LOW : HIGH));
    } else if (alexa_topic.endsWith("Topic_temperature")) {
      SendTemperature();
    } else if (alexa_topic.endsWith("Topic_humidity")) {
      SendHumidity();
    } else if (alexa_topic.endsWith("Topic_alarm")) {
      digitalWrite(alarm, (alexa_command.endsWith("on") ? HIGH : LOW));
    } else if (alexa_topic.endsWith("Topic_photo")) {
      TakePhoto();
    }
  }
}

//Reconnect to MQTT broker if lost connection
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(clientId)) {
      Serial.println("MQTT broker connected");
      client.subscribe(topic);
    } else {
      Serial.print("Failed, rc = ");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup()
{
  Bridge.begin();
  delay(2000);
  
  Serial.begin(115200);
  Serial.println("Init Arduino Home Controller v2.1...");
  
  pinMode(alarm, OUTPUT);
  pinMode(room_light, OUTPUT);
  pinMode(kitchen_light, OUTPUT);
  pinMode(garage_light, OUTPUT);
  pinMode(livingroom_light, OUTPUT);

  digitalWrite(room_light, HIGH);
  digitalWrite(kitchen_light, HIGH);
  digitalWrite(garage_light, HIGH );
  digitalWrite(livingroom_light, HIGH);

  // Define PubNub MQTT broker
  client.setServer(mqtt_server, mqtt_server_port);
  client.setCallback(callback);
  client.connect(clientId);
  Serial.println("Connected to PubNub MQTT broker OK ...");
  client.subscribe(topic);
  Serial.println("Suscribe to topic at MQTT broker Ok ...");

  dht.begin();
  //Wait for sensor initialize
  delay(4000);
  Serial.println("DHT sensor Ok ...");
}

void loop()
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

AHC_SendEmail.py

Python
File to be installed in Arduino Yun OpenWRT linux to help send email with attached photo
import smtplib
import sys
import time

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email import encoders
 
fromaddr = "joseacruzp@gmail.com"
toaddr = "joseacruzp@gmail.com"
emailpassword = "YOUR PASSWORD"
subject = "Arduino Home Controller by Alexa Skill"
body = "Photo taken in " + time.strftime('%a, %d %b %Y %H:%M:%S %Z(%z)')
filedir =sys.argv[1]
filename = sys.argv[2]

msg = MIMEMultipart()
 
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = subject
 
msg.attach(MIMEText(body, 'plain'))
 
attachment = open(filedir + filename, "rb")
 
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
 
msg.attach(part)
 
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, emailpassword)
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()

index.js

JavaScript
AWS Lambda Function if you select option 2, build your own skill
// Alexa SDK for Arduino Home Controller
// Copyright (c) 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. Use is subject to license terms.
// Jose Cruz https://sites.google.com/view/jriot 

// Define connection to PubNub 
var PubNub = require("pubnub");
var pubnub = new PubNub({
    ssl: true,
    publish_key: "pub-c-e93def7f-95aa-475a-aa60-cc3cd32ee8a7",
    subscribe_key: "sub-c-ec04dbbc-0893-11e8-8e75-cea83f8405bb",
    uuid: "YOUR UUID"
});

// Define the PubNub channel
var channel = 'AHC_IOT_01';
// Used to receive some values (temperature, humidity)
var channel2 = 'AHC_IOT_02';

// Define slot states for light and alarm turn on/off
var slotStates = ['on', 'off'];

// App ID for the skill
var APP_ID = 'YOUR APP ID FOR THE SKILL';

// The AlexaSkill prototype and helper functions
var AlexaSkill = require('./AlexaSkill');

var ArduinoHomeSkill = function() {
    AlexaSkill.call(this, APP_ID);
};

//Listener for suscribe and receive temperature and humidity
var mqttListener;

var access_token;
var url;
var https = require("https");


function SendMessage(topicname, commandvalue, speechOutput, iresponse) {
    https.get(url, res => {
        res.setEncoding("utf8");
        let body = "";
        res.on("data", data => {
            body += data;
        });
        res.on("end", () => {
            pubnub.publish({ //Publishes the turn message to my PubHub Device.
                channel: channel,
                message: {
                    "topic": topicname,
                    "command": commandvalue,
                    "id": JSON.parse(body).email
                }
            }).then((response) => {
                console.log("message Published w/ timetoken", response.timetoken);
                if (speechOutput) iresponse.tell(speechOutput);
            }).catch((error) => {
                console.log("publishing failed w/ status: ", error);
                iresponse.ask("Sorry, I didn't catch what you said");
            });

        });
    });
}


/// Extend AlexaSkill
ArduinoHomeSkill.prototype = Object.create(AlexaSkill.prototype);
ArduinoHomeSkill.prototype.constructor = ArduinoHomeSkill;

ArduinoHomeSkill.prototype.eventHandlers.onSessionStarted = function(sessionStartedRequest, session) {

    //    SetUserID();

    console.log("ArduinoHomeSkill onSessionStarted requestId: " + sessionStartedRequest.requestId +
        ", sessionId: " + session.sessionId);
    //    console.log("Init...");

    //Delete all listeners and suscribes defined 
    pubnub.removeListener(mqttListener);
    pubnub.unsubscribeAll();

    //    console.log("Init...Ok");

};

//-------->This is invoked by invocation word "Arduino Home"
ArduinoHomeSkill.prototype.eventHandlers.onLaunch = function(launchRequest, session, response) {
    console.log("ArduinoHomeSkill onLaunch requestId: " + launchRequest.requestId + ", sessionId: " + session.sessionId);
    //if no amazon token, return a LinkAccount card

    if (session.user.accessToken == undefined) {

        response.tellWithCardLink('To start using this skill, please use the companion app to authenticate on Amazon.');

        return;

    }

    var speechOutput = "Welcome to Arduino Home Controller.   What would you like to do?";
    var repromptText = "I am ready";
    response.ask(speechOutput, repromptText);
};

ArduinoHomeSkill.prototype.eventHandlers.onSessionEnded = function(sessionEndedRequest, session) {
    console.log("ArduinoHomeSkill onSessionEnded requestId: " + sessionEndedRequest.requestId +
        ", sessionId: " + session.sessionId);

    console.log("End...");

};



//*** Define all intent handlers
ArduinoHomeSkill.prototype.intentHandlers = {
    //*** AboutIntent handler
    "AboutIntent": function(intent, session, response) {
        var myText;
        console.log("in about");
        myText = "Arduino Home Controller skil let you control internet connected devices. It controls  Lights at room, kitchen, garage or living room), read a temperature sensor to scan home temperature, read Humidity sensor to scan home humidity, uses webcam to take a home security photo and sent it by email and activate an alarm to alert some events. It uses PubNub site to manipulate all messages send by Alexa with Lambda function. Please check information at skill page for more details.   What would you like to do?";
        response.ask(myText);
        return;
    },

    //*** LightIntent handler
    "LightIntent": function(intent, session, response) {
        var slotHabRooms = ['room', 'kitchen', 'garage', 'living room'];

        var lightSlot = intent.slots.light;
        var lightSlotValue = lightSlot ? lightSlot.value : "";

        var whichSlot = intent.slots.which;
        var whichSlotValue = whichSlot ? whichSlot.value : "";
        if (lightSlotValue && whichSlotValue && slotStates.indexOf(lightSlotValue.toLowerCase()) > -1 && slotHabRooms.indexOf(whichSlotValue.toLowerCase()) > -1) {

            SendMessage('Topic_' + whichSlotValue, lightSlotValue, "The light is now " + lightSlotValue, response);

        }
        else {
            response.ask("Sorry, I didn't catch what you said");
        }
    },

    //*** AlarmIntent handler
    "AlarmIntent": function(intent, session, response) {
        var alarmSlot = intent.slots.alarm;
        var alarmSlotValue = alarmSlot ? alarmSlot.value : "";
        if (alarmSlotValue && slotStates.indexOf(alarmSlotValue.toLowerCase()) > -1) {
            SendMessage('Topic_alarm', alarmSlotValue, "The alarm is now " + alarmSlotValue, response);
        }
        else {
            response.ask("Sorry, I didn't catch what you said");
        }
    },

    //*** TakePhotoIntent handler
    "TakePhotoIntent": function(intent, session, response) {

        SendMessage('Topic_photo', 'take', "Taken home photo ", response);

    },
    //*** GetTemperatureIntent handler
    "GetTemperatureIntent": function(intent, session, response) {

        mqttListener = {
            status: function(statusEvent) {},
            message: function(message) {
                // handle message
                console.log("Receive=", message);
                var myText = "Inside Temperature is " + message.message + " degrees C";
                response.tell(myText);
            },
            presence: function(presenceEvent) {
                // handle presence
            }
        };
        pubnub.addListener(mqttListener);
        pubnub.subscribe({
            channels: [channel2]
        });
        SendMessage('Topic_temperature', 'Ok', null, response)
    },


    //*** GetTemperatureIntent handler
    "GetHumidityIntent": function(intent, session, response) {
        mqttListener = {
            status: function(statusEvent) {},
            message: function(message) {
                // handle message
                console.log("Receive=", message);
                var myText = "Inside Humidity is " + message.message + " %";
                response.tell(myText);
            },
            presence: function(presenceEvent) {
                // handle presence
            }
        };

        pubnub.addListener(mqttListener);

        pubnub.subscribe({
            channels: [channel2]
        });

        SendMessage('Topic_humidity', 'Ok', null, response)
    },

    //*** HelpIntent handler
    "AMAZON.HelpIntent": function(intent, session, response) {
        response.ask("With Arduino Home Controller skill and Alexa you can control internet connected devices using an Arduino Yun or Arduino with Ethernet Shield. Please check information at skill page for more details.    What would you like to do?");
    },
    //*** StopIntent handler
    "AMAZON.StopIntent": function(intent, session, response) {
        response.tell("Thanks for using Arduino Home Controller. Bye see you later");
    },
    //*** StopIntent handler
    "AMAZON.CancelIntent": function(intent, session, response) {
        response.tell("Thanks for using Arduino Home Controller. Bye see you later");
    },
    default: function(intent, session, response) {
        response.ask("Try again");
    },

};


// Create the handler that responds to the Alexa Request.
exports.handler = function(event, context) {

    try {
        access_token = event['context']['System']['user']['accessToken'];
        url = 'https://api.amazon.com/user/profile?access_token=' + access_token;
        //console.log("Access Token:", access_token);
    }
    catch (error) {
        console.log(error);
    }

    // Create an instance of Arduino Home Skill
    var ArduinoHomeControl = new ArduinoHomeSkill();
    ArduinoHomeControl.execute(event, context);
    //console.log('AWSrequestID =', context.awsRequestId);
};

Github

Credits

Jose Cruz

Jose Cruz

5 projects • 15 followers

Comments