Project tutorial
Wise Chameleon - Turn Anything Into a Smart Device!

Wise Chameleon - Turn Anything Into a Smart Device! © CC BY

We want to combine DIY electronics and 3D printing to turn anything into a smart device.

  • 6,395 views
  • 0 comments
  • 16 respects

Components and supplies

Necessary tools and machines

3drag
3D Printer (generic)

Apps and online services

Adafruit.io
Dp image kit 02
Amazon Alexa Alexa Skills Kit
Autodesk fusion 360 logo 4szx21llea
Autodesk Fusion 360
Used for designing 3D printed components

About this project

wisechameleon.com

Update: We are so excited to have won the competition, thanks to everybody who supported us and of course to the judges. :) We are already continuing development on this project to make it more user-friendly, easier to adopt and of course add more attachments so it can do more cool stuff. Please check back frequently and let us know what you think of our progress.

IoT for the WIN!

Let's do something different in the smart home space! Something next level not just turning on lights. Let's see if we can get it to a kick-startable level!

After some discussion on various topics, we pinned down our starting project definition to "smart device controlled modular actuators."

We would like to produce a ready-to-use device which will have a servo/motor head that can accept adapters (3D-printed or molded) and triggered by an app or smart hub.

This will leverage on a couple of things, first the modularity that will be very exciting for growing makers community and 3D printer owners, and also the growing smart home DIY electronics. This will be helpful in transforming non-smart devices (blinds, etc) and also come up with new applications (watering plants) through various adapters.

Components

A board capable of:

  • Running a motor/servo
  • WiFi communication with Alexa/Google/Smart Hub
  • Power management for handling battery/solar/DC Power
  • Servo/motor
  • Power source
  • Use case defined attachments
  • Website - ios/android app
  • Alexa skill integration

INITIAL IMPLEMENTATION

We use Arduino MKR1000 board connected to the Adafruit.IO device cloud. And Alexa skills is developed as an AWS Lambda function that implements amazons Smart Home Skill Kit Inteface. In particular it implements the PowerController and PowerLevelController as well as custom scenes.

Used components:

  • AWS Lambda -
  • cloudwatch logs, to debug alexa req / resp mss
  • Amazon Developer Account (where Lambda definition and publish abilities lie)
  • Adafruit.io the device cloud to control our Arduinos
  • Test echo virtual device (just sign in as chameleon wise developer account) - https://echosim.io/

Here be the AWS Lambda code that Implements the Alexa Smart Home Skill API needed for integration of Chameleon Wise's /dev device (alexa controlled servo).

Detailed info on the Smart Home Skill API is here: https://developer.amazon.com/docs/smarthome/understand-the-smart-home-skill-api.html

Deployment:

$ cd AlexaSmarthomeAPI_Chameleon$ pip install requests -t .$ pip install nodb -t .

Now since our alexa skill is python3 and nodb doesn't support python3 make the following changes to AlexaSmartHomeAPI_Chameleon/nodb/__init__.py

line 69 -> bytesIO.write(bytes(serialized, 'utf-8')) line 241 -> if index in obj: line 264 -> return self.hash_function(bytes(index_value, 'utf-8')).hexdigest()

once the file is modified you are read to deploy to Lambda from AlexaSmarthomeAPI_Chameleon directory do:

$ zip -r python.zip .

This will zip everything up, then navigate to the Lambda page

Under Function Code select Upload a Zip File then select the python.zip file upload it and click save. Now you can test it out.

There are three things to test

  • Discovery... navigate to https://alexa.amazon.com/spa/index.html#appliances login with the chameleonwise user
  • Forget all device
  • Click discover A device called moto should appear (if you are using the smart phone app, you will get a device controler for this guy that looks like a power switch). Your now setup and ready to go

To test out the functionality use the following uterance

Alexa turn moto on alexa turn moto off alexa setup power level to 100 on moto

Debugging:

To check whats happening with the Lambda, check out the CloudWatch Logs

Use Cases

After testing the system on breadboard, we made a case for MKR1000 and continuous servo (check our thingiverse page for the 3D models https://www.thingiverse.com/wise_chameleon/designs). Soldering was a bit tedious, but eventually worked.

Designed an adapter for the blind wand, and also one with a gear that can be used on a sliding door, which we used for a pet feeder.

We documented all our code and steps on our GitHub repo

https://github.com/WiseChameleon/ChameleonAlexa

Here is a video tour of the project.

Useful documentation URLS:

Code

MKR1000 codeC/C++
This is the code that is uploaded to MKR1000 (along with config file)
#include "config.h"
#include <Servo.h>

// pin used to control the servo
#define SERVO_PIN 5
#define SERVO_STOP 90
#define SERVO_LEFT 180
#define SERVO_RIGHT 0

// create an instance of the servo class
Servo servo;
const int servoPin = 5;
const int button1Pin = 4;
const int button2Pin = 3;
int spd = 90;    // variable to store the servo speed
int old_buttonState1;
int old_buttonState2;

// set up the 'servo' feed
String servo_switch_feed;
String servo_pos_feed;
AdafruitIO_Feed *servo_switch;
AdafruitIO_Feed *servo_pos;

void setup() {
   // start the serial connection
  Serial.begin(115200);
  while(! Serial);

  servo_switch_feed = String(UUID) + "-servo";
  servo_pos_feed = String(UUID) + "-servo_pos";
  Serial.println(servo_switch_feed);
  Serial.println(servo_pos_feed);
  servo_switch = io.feed(servo_switch_feed.c_str());
  servo_pos = io.feed(servo_pos_feed.c_str());

  servo.attach(SERVO_PIN);
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);
  old_buttonState1 = digitalRead(button1Pin);
  old_buttonState2 = digitalRead(button2Pin);
  servo.write(SERVO_STOP);

  // connect to io.adafruit.com
  Serial.print("Connecting to Adafruit IO");
  io.connect();
  servo_switch->onMessage(handleOnOff);
  servo_pos->onMessage(handlePos);

  // wait for a connection
  while(io.status() < AIO_CONNECTED) {
    //Serial.print(".");
    Serial.println(io.statusText());
    delay(500);
  }

  // we are connected
  Serial.println();
  Serial.println(io.statusText());

  //reset servo pos to 90
  servo_pos->save(SERVO_STOP);
  servo_switch->save("ON");
}


void loop() {

 int buttonState1;
 int buttonState2;
 buttonState1 = digitalRead(button1Pin);
 buttonState2 = digitalRead(button2Pin);

 if (buttonState1 == LOW) {
  Serial.println("button one pressed");
   spd = 180;
   servo.write(spd);
   delay(250);
   old_buttonState1 = buttonState1;
 }
 else if (buttonState2 == LOW) {
   Serial.println("button two pressed");
   spd = 0;
   servo.write(spd);
   delay(250);
   old_buttonState2 = buttonState2;
 }
 if (old_buttonState1 != buttonState1) {
  old_buttonState1 = buttonState1;
  servo.write(SERVO_STOP);
 }
 if (old_buttonState2 != buttonState2) {
  old_buttonState2 = buttonState2;
  servo.write(SERVO_STOP);
 }
  // io.run(); is required for all sketches.
  // it should always be present at the top of your loop
  // function. it keeps the client connected to
  // io.adafruit.com, and processes any incoming data.
  io.run();

}


void handleOnOff(AdafruitIO_Data *data) {

  char* on_off = data->toChar();
  Serial.println(on_off);
 

  if (strcmp(on_off, "ON") == 0)
    Serial.print("turned on");
  else if (strcmp(on_off, "OFF") == 0) {
    Serial.print("turned off");
    servo.write(SERVO_STOP);
    servo_pos->save(SERVO_STOP);
  }
  else if ((strncmp(on_off, "S", 1) == 0 ) || (strncmp(on_off, "T", 1) == 0)){
    //This is a command in the form S20:T2:S90 ...
    // where S sets the speed and T waits
    Serial.print("We got a command string");
    char *cmd;
    cmd = strtok (on_off,":");
    while (cmd != NULL) {
      if (strncmp(cmd, "S", 1) == 0 ) {
        //set speedk
        cmd++;
        int cmd_int = atoi(cmd);
        servo_pos->save(cmd_int);
        startServo(cmd_int);
      } else if (strncmp(cmd, "T", 1) == 0) {
        cmd++;
        int cmd_int = atoi(cmd) * 1000;
        delay(cmd_int);
      }
      cmd = strtok(NULL, ":");
    }
  }
}

void handlePos(AdafruitIO_Data *data) {

  // convert the data to integer
  int angle = data->toInt();

  startServo(angle);
}

void startServo(int angle) {
 
 // make sure we don't exceed the limit
  // of the servo. the range is from 0
  // to 180.
  if(angle < 0)
    angle = 0;
  else if(angle > 180)
    angle = 180;

  servo.write(angle);

}
Wise Chameleon Github Repo
This contains all setup details, and codes used for this project

Custom parts and enclosures

Chameleon Thingiverse Designs

Schematics

Sketch (mkr1000 was replaced)
Fritzing did not have mkr1000, so I choose another board. Please check the photos of the setup
Screen shot 2018 02 25 at 1 41 08 am 2xd4bbawkn
Photo of setup
20180219 214622 o5zvccmmnz

Comments

Similar projects you might like

Scent-terrific Smart Candle

Project tutorial by Darian Johnson

  • 2,907 views
  • 0 comments
  • 32 respects

Rampiot - Cool Smart Lock

Project tutorial by Robinson Mesino

  • 3,693 views
  • 1 comment
  • 23 respects

BOFF - Alexa Enabled Open Smart Fan

Project showcase by Stephen Harrison

  • 7,699 views
  • 6 comments
  • 28 respects

Alexa, Turn On THIS Lamp: Smart 3D Sensor for Amazon Echo

Project tutorial by 3 developers

  • 4,162 views
  • 6 comments
  • 26 respects

Smart Bird Feeder

Project showcase by Team ESIEE-Amiens Students

  • 2,682 views
  • 8 comments
  • 13 respects

Alexa Smart Power Strip with Temperature

Project tutorial by Muhammad Afzal

  • 1,203 views
  • 0 comments
  • 7 respects
Add projectSign up / Login