Dooreo can open your door when you can't or don't want to. Use it to let your friends in without getting up from the couch or open your door when your hands are full.
Dooreo uses stepper motors and 3D-printed parts to physically operate the door and a combination of Raspberry Pi and Arduino to control it. The Raspberry interfaces with AWS to allow control through Amazon Alexa.
Here's a video of Dooreo in action.
Development ProcessI began by verifying the electrical hardware setup. I was planning to use 2 stepper motors controlled by an arduino through an easy driver and a big easy driver. The arduino would get signals from the raspberry pi which would get information from the amazon skill.
I had done a previous project where I used Alexa to control a raspberry pi but I wanted to go through the proper AWS channels this time instead of using the ngrok shortcut that is not really a permanent solution. Working through setting up an Alexa Skill, Lambda Function, IoT Thing and having the pi listen for delta events for the Thing Shadow proved to be a challenging but rewarding process. Initially I thought to use an Alexa Smart Home Skill as the interaction is pre-built and would save me some effort. However, Smart Home Skills aren't allowed for doors. This is for a good reason as they don't support any sort of pin or passphrase. Instead, I developed a custom skill and Lambda handler to allow for opening and closing the door with a four digit pin. I'll try to explain it as best I can to make it easier for any who follow down this path.
Communicating between a raspberry pi and arduino is very straightforward as the arduino can use the raspberry pi's usb interface. Wiring up all of the motor wires is always a bit of a task but presented no real hurdles.
In the electrical setup my main issue was discovered later. I wanted to use a 6V wall adapter I had available. However, when I tried to actually move the door knob with this 6V source powering my stepper motor the motor could not provide enough torque. I ended up having to upsize to a bigger power supply that operates at 24V.
The next step was to figure out the mechanisms to turn the door knob and open the door. For the doorknob I initially wanted to use a timing belt and to open it I wanted to use a winch.
To attach the timing belt to the door knob I had to clamp a timing belt pulley to the door knob. I took some rough measurements and modeled some corresponding pieces in Solidworks and printed them out.
The clamping on the doorknob worked pretty well but the timing belt was not able to provide enough force. I decided to change to a gear mechanism. I was able to keep the same geometry as I had for the timing belt and use gear models from McMaster-Carr to design my needed mechanism.
The Arduino connects to the Raspberry Pi with an ftdi adapter from the programming header of the Arduino to the usb port of the raspberry pi.
The Arduino can be powered through its connection to the raspberry pi, and the logic voltage for the easy drivers can be supplied by the arduino, this is the "5V" reference.
The motor drivers are powered by a separate 24V source. Connect this to "PWR IN" at "V+" and "GND", make sure to get the polarity right. The motors connect to the easy drivers at the "MOTOR" pins. Wiring color can be somewhat unreliable so the best thing to do is identify the two wires that comprise a coil and connect these together to A and B. So take the wires in pairs and measure their resistance The pairs that have low resistance between them are coils. Connect the first coil to the two "A" pins and the other coil to the two "B" pins.
Lastly, connect the arduino to the two easy drivers. You need to wire a digital pin from the arduino to each of the following pins on the easy drivers: STP, DIR, EN, MS1, MS2 and if you are using a big easy driver MS3. If your pin assignments don't match mine you'll have to change them in the arduino sketch to match.
I used the box my parts came in from Sparkfun as an enclosure for the electronics.
We'll want to set up the raspberry pi headless so that we can ssh into it and reprogram the Arduino without needing to access the enclosure. Here's a pretty decent tutorial on setting up the raspberry pi
http://www.circuitbasics.com/raspberry-pi-basics-setup-without-monitor-keyboard-headless-mode/
and one for Mac:
https://lifehacker.com/the-always-up-to-date-guide-to-setting-up-your-raspberr-1781419054
and if you don't want to do this headlessly here's the regular way to do it with a temporary keyboard, mouse and monitor:
https://www.instructables.com/id/My-Raspberry-Pi-Setup/
Once your raspberry pi is set up we'll want to ssh in with x11 forwarding enabled. So install Xming: https://sourceforge.net/projects/xming/files/ and make sure it's running. Then, use Putty: https://www.putty.org/ with Enable X11 Forwarding selected:
Once SSH is established with your pi use the following commands to install arduino
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install arduino
Then run it from the terminal by typing "arduino". It will take a second to come up but you should see the Arduino IDE on your computer.
Make sure to select the correct microcontroller and com port (it's probably /dev/ttyUSB0 but if it's not use "lsusb" in your terminal to list the devices and find your arduino).
Next we'll program the Arduino to control the motors when it receives a command. The raspberry pi will send it a byte for open and a byte for close. On open, the Arduino should move the doorknob motor far enough to unlatch the door and then turn the winch motor far enough to open the door. These parameters will probably change from door to door, I found them by trial and error.
First, we set up the pin definitions:
#define stp 2
#define dir 3
#define MS1 4
#define MS2 5
#define EN 6
#define stpb 12
#define dirb 7
#define ENb 11
#define MS1b 8
#define MS2b 9
#define MS3b 10
Then we set all of the pins as outputs and start up the serial connection.
void setup() {
pinMode(stp, OUTPUT);
pinMode(dir, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(EN, OUTPUT);
pinMode(stpb, OUTPUT);
pinMode(dirb, OUTPUT);
pinMode(MS1b, OUTPUT);
pinMode(MS2b, OUTPUT);
pinMode(MS3b, OUTPUT);
pinMode(ENb, OUTPUT);
Serial.begin(9600); //Open Serial connection for debugging
}
Our main loop just listens for a serial command and makes sure not to call the open and close door functions unless there's a state change.
//Main loop
void loop() {
while(Serial.available()){
user_input = Serial.read(); //Read user input and trigger appropriate function
if(user_input =='5')
{
if(onOffState==0){
openDoor();
}
onOffState=1;
}
else if(user_input=='6')
{
if(onOffState==1){
closeDoor();
}
onOffState=0;
}
else
{
Serial.println("Invalid option entered.");
}
}
}
We write functions for controlling the motors that take direction, number of steps and speed (in microseconds delay between steps) so that we can easily change the behavior of the motor by just modifying our calls to these functions.
void turnKnob(int dirValue, int steps, int motorSpeed)
{
digitalWrite(dir,dirValue);
for(x=1;x<steps;x++)
{
digitalWrite(stp,HIGH);
delayMicroseconds(motorSpeed);
digitalWrite(stp,LOW);
delayMicroseconds(motorSpeed);
}
}
void turnWinch(int dirValue, int steps, int motorSpeed)
{
digitalWrite(dirb,dirValue);
for(x=1;x<steps;x++)
{
digitalWrite(stpb,HIGH);
delayMicroseconds(motorSpeed);
digitalWrite(stpb,LOW);
delayMicroseconds(motorSpeed);
}
}
Finally, we write functions that make the appropriate calls to the motor control functions in order to open and close the door. One thing of note is for the winch I had to call the function multiple times as the step size is too large for the standard int variable (I could also just use a larger type).
void openDoor()
{
Serial.println("opening door");
turnKnob(0,250,1000);
//wind in winch
turnWinch(0,20000,90);
turnWinch(0,20000,90);
turnWinch(0,20000,90);
turnWinch(0,20000,90);
}
void closeDoor()
{
Serial.println("closing door");
digitalWrite(EN,HIGH);
//winch out door
turnWinch(1,20000,60);
turnWinch(1,20000,60);
turnWinch(1,20000,60);
turnWinch(1,20000,60);
digitalWrite(ENb,HIGH);
}
Step 4: Install HardwareI use a lot of double sided tape in this installation. The specific tape I'm using is almost scary strong "Scotch Extreme Mounting Tape"
First, attach the gear to your doorknob. This is accomplished by sliding the back plate over the doorknob behind it, and then screwing the gear portion onto it with 4-40 x 1" screws and nuts. The part relies on the friction created with clamping force so it's important to tighten the screws quite tight.
Next, mount the knob-motor to the door. The smaller gear is fit onto the shaft of the motor (held in place by gorilla glue). Line the small gear up with the gear on the door knob such that the gears mesh and tape the motor in place with mounting tape.
Next we mount the winch assembly. The winch assembly is two 3D-printed parts, the spool and the bracket. Slide the spool onto the bracket's pole, then slide the motor's shaft into the spool's hole and attach the motor with 4-40 x 1" screws and nuts.
Then, measure how long a string needs to be to reach from the winch to an opposing wall. Cut a length of string and insert this through the hole in the middle of the spool. Secure it using a knot.
Now, mount the winch assembly to the door using mounting tape.
Lastly, we mount the electronics to the door and rout power to it. I used an extension chord and a usb charger and mounting tape or gorilla tape to secure everything.
In order to get Alexa to send directions to the Raspberry Pi we will set up an Alexa skill, a Lambda function for it to call, and an AWS IoT Thing for the Lambda function to update. The Raspberry Pi will then detect changes in the AWS IoT Thing and respond appropriately.
Navigate to the aws console. Create an account if you don't have one.
https://console.aws.amazon.com/
In "AWS services" type "iot" and click on "AWS IoT".
Then go to "Manage" in the side menu and click in the top right for "Create".
Select "Create a single thing", name it "Dooreo", you don't have to do anything else on this page, no type, no group, no attributes. Click Next.
Select "Create certificate". On the next page it's very important to download all of the files AND save the root CA. For the root CA just save it to a text file, don't worry about the name (We'll name it later (root-CA.crt))
Click "Activate" and then "Done"
Next, go to "Secure" -> "Policies" in the Side Menu. Click in the top right "Create"
Name it "Dooreo Policy" and in action put "iot:*", in "Resource ARN" put "*" and then check "Allow" then click "Create"
Go to "Secure" -> "Certificates" and find the certificate you just created. Click on the three dots, select "Attach policy" and select Dooreo Policy. Click on the three dots again and select "Attach thing" and select Dooreo.
To have the Raspberry Pi react to commands from Alexa we'll be using the python version of aws-iot-device-sdk. Their github page does an excellent job explaining it and how to install it.
https://github.com/aws/aws-iot-device-sdk-python
Basically we'll be using the same functionality as the BasicShadow sample. Scroll through the ReadMe till the part that describes the BasicShadow sample and make sure you get that running properly.
When you go to run the command to start basicShadowDeltaListener.py and basicShadowUpdater.py you'll need the endpoint name and certificate files from the thing you created. Put these in the sample folder and rename them easy names. I use WinSCP to put files on my Raspberry Pi.
https://winscp.net/eng/download.php
-"certificate.pem.crt"
-"root-CA.crt"
-"private.pem.key"
You can find the endpoint by going to the aws console, going to "Manage" -> "Things" clicking on "Dooreo" and then going to "Interact". The first field is your endpoint.
So open up two SSH sessions for your Raspberry Pi and go to the folder for basicShadow. In the first, run basicShadowDeltaListener
python basicShadowDeltaListener.py -e <endpoint> -r root-CA.crt -c certificate.pem.crt -k private.pem.key
and in the second SSH session run basicShadowUpdater
python basicShadowUpdater.py -e <endpoint> -r root-CA.crt -c certificate.pem.crt -k private.pem.key
Makes sure that in the basicShadowDeltaListener you see messages coming in that look like the picture:
If you verified that this works, congratulations you have you Raspberry Pi communication with AWS.
Now put "dooreo.py" in the same folder and replace your endname on line 65.
Run this in tmux. If you aren't familiar with tmux. It's a virtual terminal that you can run on a linux environment. I use it so that when I close my ssh session the processes that I run stay running. Install it by running
sudo apt-get install tmux
Then open a tmux session by typing "tmux" and run
python3 dooreo.py
Step 7: LWAThis post has a good explanation of how to set up LWA for linking an Alexa skill to a Lambda Function. Only do step 1:
Make sure to get the Client ID and Client Secret. Once you have this you can move on to step 8
8.1) Go to the aws console. In "AWS services" type "Lambda" and select it to go to the Lambda console.
8.2) Select "Create function" in the top right
8.3) Choose "Author from scratch", name it "Dooreo-Lambda", select "Python 2.7" as the runtime, select "Choose an existing role" and select "lambda_basic_execution" as the role.
8.4) The "role" "lambda_basic_execution" refers to an IAM role. Let's make sure to set that up correctly. Go back to the start page for the aws console. Type in IAM and select it.
8.5) Select "Roles" in the side menu and select "lambda_basic_execution"
8.6) Go to "Attach Policy" and select AWSIoTFullAccess and AWSIoTDataAccess and click "Attach"
8.7) In order to finish the configuration for the Lambda function we'll need an Alexa skill ID to fill in. In another tab from where you are setting your Lambda Function, go to the amazon developer console. If you don't have an account yet, make one (you will have had to make one for Step 7). and go to "Alexa" and click on "Get Started >" under "Alexa Skills Kit"
https://developer.amazon.com/edw/home.html#/
8.8) Click on "Add a New Skill" in the top right.
8.9) In "Skill Information" Select "Custom Skill" and name it "Dooreo Skill". Give it the invocation name "dooreo". Once you hit "Save" the page will update and show you the Application Id.
8.10) Go back to your Lambda function and go to the configuration page. In the "Add triggers" list click on Alexa Skills Kit. Copy the "Application Id" into the "Configure triggers" area under Application ID. Click "Add" then "Save" in the top right.
8.11) In "Configuration" click on "Dooreo-Lambda". Copy the code from "lamba.py" into the "Function code" section. If you've made any changes, make sure "thingName" on line 17 matches your thing name. Click "Save" in the top right.
This code is all about interpreting the Json from Alexa. Alexa will send its commands in this format and the Lambda function needs to interpret it and decide what to do. Refer to the code comments for explanation about its behavior.
9.1) Now it's time to set up the Alexa Skill. Go back to your Alexa Skill. In "Configuration" copy the ARN from your Lambda function into the "Endpoint" section. Use "https://www.amazon.com/ap/oa" in "Authorization URL". Get the client ID from your LWA profile. Add "profile" to the Scope. Use "https://api.amazon.com/auth/o2/token" as your Access Token URI. Get the Client Secret from your LWA profile. If you want to publish a skill you'll have to maintain a privacy policy page and link it here.
9.2) In the side menu go to "Interaction Model" we'll be using "Builder" (currently in BETA)
9.3) You can take the code provided under "Alexa Skill" and paste it into the "Code Editor" to generate the behavior or build it step by step.
9.4) To build it step by step we'll need to add 3 intents. Next to Intents in the side menu, click add. Name your first intent changeDoorState and click create.
9.5) Add some sample Utterances for this intent such as "{doorState} door with pin {pin}" (see pictures). The words in braces are slots. We'll add those next.
9.6) Add the slot "pin" and give it the type AMAZON.FOUR_DIGIT_NUMBER.
9.7) Add the slot "doorState" and create a new type for it called "state"
9.8) Configure the state type by clicking on it in the side menu and adding its possible values with synonyms as shown in the picture
9.9) Add the clearPin intent with the pin slot and the setPin intent with the pin slot
9.10) Click on "Build Model" in the top bar and you should be all set.
In your Alexa skill go to the test section and bring up the Test Simulator (currently in BETA). Type in "ask Dooreo setPin to one two three four" you should get the response "updated pin"
Then try "ask dooreo open door" this should initiate the dialogue and Alexa should ask "What's the pin" type in "one two three four" and she'll respond "door open"
At this point everything should be working independently and it's time to tie it all together.
Make sure your hardware is securely mounted.
Make sure your electronics are wired and powered on.
Make sure your Arduino is running the proper code.
Make sure your Pi can see the Arduino (/dev/ttyUSB0)
Make sure you Pi is running dooreo.py in a tmux session.
From the "Test Simulator" run type in "ask dooreo open door" and your motor should run and the door should open. If this is the case, congrats!
Step 12: Echo SetupThe last step to use this with your voice is to enable this for your echo device.
Go to your Alexa companion app on your smartphone. Go to "Skills" in the side menu. Go to "Your Skills" in the top right. Switch from "Recently Added" to "All Skills". Find "Dooreo". Click on "Enable". It should do the account linking as long as you've set up the LWA parameters correctly.
Congrats, you can now open your door with your voice!
Comments