Most wireless outlets like Wink and SmartThings cost around $70, and then each additional outlet can cost another $50! Older remote control outlets, like this one from Etekcity, can be as cheap as $5 an outlet!
The problem is, they don't have all those fancy voice and Wi-Fi features the new ones do, that's what this tutorial is going to help you solve!
We'll be using a Raspberry Pi (any model will do, but the pins might be different!), a 433 Mhz Transmitter/Receiver to communicate with the wireless outlets, and some Female-Female Wire Jumpers. You'll also need an AWS account to setup the Alexa, IoT and Lambda portions. Altogether it should cost about $50 for everything!
There's no hard language dependency, all of the libraries I use are basic and written in multiple languages. I normally write everything in Javascript, but this tutorial will be Python to better match other Raspberry Pi tutorials.
All IDs in this tutorial were deleted after completion, so don't worry about everyone being able to see my authentication secrets!Preparing the Raspberry Pi Operating System
We start with the Raspberry Pi's operating system. Your Pi may have come with an SD card with the operating system already good-to-go, or you might have an SD card with NOOBS. Either of those will work, but you can also follow the official tutorials to prepare your own SD card. For the next step I'll assume you have the operating system installed and your Pi booted up.
Connecting to the PiYou can easily get started using a Keyboard/Mouse/Monitor, but you will be able to do everything using just SSH so all you really need is an Ethernet cable. Here's a longer tutorial on how to do things using only an Ethernet cable and Adafruit has a tool, but on my Mac it was as simple as plugging one in and starting SSH in Terminal (default password is raspberry
):
$
The authenticity of host 'raspberrypi (10.10.10.74)' can't be established.
ECDSA key fingerprint is SHA256:NcxFUmKkMfan0WozFOVFli9qDmBnwP5MC1ZkrgK29pM.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'raspberrypi,10.10.10.74' (ECDSA) to the list of known hosts.
pi@raspberrypi's password: raspberry
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri May 27 11:50:32 2016
pi@raspberrypi:~ $
Installing DependenciesOnce you're there we can begin installing our first dependency: pi-switch-python, which in turn has its own dependencies. Their page will have the most up-to-date instructions, but the main commands are below for convenience. Note libboost
can take a LONG time, mine took half an hour!
From now on I won't include the output of the commands, just the current directory, and the commands themselves (everything after the dollar sign)
~ $ cd wiringPi
~/wiringPi $ ./build
~/wiringPi $ sudo apt-get update
~/wiringPi $ sudo apt-get install python-dev libboost-python-dev python-pip
~/wiringPi $ sudo pip install pi_switch
Installing AWShomeThe final installation step is the actual AWShome library, which just needs to be cloned:
~/wiringPi $ cd ~
~ $ git clone https://github.com/rajington/AWShome
Wiring up the ComponentsBoth the schematic and the picture below use matching colors. I used a breadboard and a Pi Cobbler to make it easier to show, but they aren't necessary if you use Female-Female jumpers.
When the Etekcity remote's buttons are pressed, it emits a small radio signal. Once you've put batteries in the remote and wired up your Pi, you're ready to discover the actual codes the remote sends so we can send them without the remote. Simply run the included codes.py
helper and it will display them on the screen. For each button you plan on using, record the code, remembering that on
and off
have different codes and that codes will repeat the longer you hold down the button. I've included the 10 codes that came with my remote, but yours might be different.
~ $ cd AWShome/
~/AWShome $ sudo ./codes.py
Listening for RF codes...
Received code 283955
Received code 283955
Received code 283964
Received code 283964
Received code 284099
Received code 284099
Received code 284108
Received code 284108
Received code 284419
Received code 284419
Received code 284428
Received code 284428
Received code 285955
Received code 285955
Received code 285964
Received code 292099
Received code 292099
Received code 292108
Received code 292108
Configure the AWS CLIOnce you've registered and can login to the AWS console, you can get the credentials to configure awscli
. Below is an example:
~/AWShome $ sudo aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-east-1
Default output format [None]: ENTER
Although awscli
doesn't require sudo, our script does and it'll be looking for credentials under the root account.
Create the Things using AWS IoTWe're now ready to create some thing
s using AWS IoT. Each thing
will be a different remote outlet, and it helps to give them friendlier names than outlet-1 and outlet-2, here I create two:
~/AWShome $ sudo aws iot create-thing --thing-name floor-lamp
~/AWShome $ sudo aws iot create-thing --thing-name table-lamp
You can also create the things using the web interface.Configure AWShome
The last step is to configure the awshome.py
file to use the names you created above. Edit the file and add the new things at the bottom. I've created two additional lines for the two things I created earlier using the remote codes I found earlier:
if __name__ == "__main__":
iot = createIoT()
rf = createRF()
# Create your switches here, using the format:
# OnOff(<THING NAME>, <ON CODE>, <OFF CODE>, rf, iot)
#
# The codes should be 6 digits and can be found using "codes.py".
#
# Example (from my remote):
# OnOff('outlet-1', 283955, 283964, rf, iot)
# OnOff('outlet-2', 284099, 284108, rf, iot)
# OnOff('outlet-3', 284419, 284428, rf, iot)
# OnOff('outlet-4', 285955, 285964, rf, iot)
# OnOff('outlet-5', 292099, 292108, rf, iot)
OnOff('table-lamp', 283955, 283964, rf, iot)
OnOff('floor-lamp', 284099, 284108, rf, iot)
print('Listening...')
while True:
You must also update the endpoint with the one specific to your things, visible by selecting any thing from the IoT dashboard:
# creates thhe AWS IoT
def createIoT():
iot = AWSIoTMQTTShadowClient('AWSHome', useWebsocket=True)
# update this with your own endpoint from the IOT dashboard
iot.configureEndpoint('a1am7bjirugllj.iot.us-east-1.amazonaws.com', 443)
iot.configureCredentials(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'VeriSign-Class 3-Public-Primary-Certification-Authority-G5.pem'))
iot.configureConnectDisconnectTimeout(10) # 10 sec
iot.configureMQTTOperationTimeout(5) # 5 sec
iot.connect()
return
Testing IoTWe can now actually test to see that IoT is all working! First we download the required certificate file that AWS IoT requires.
~/AWShome $ wget https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem
Next we run awshome.py
so our things get populated with some state. If your outlets were currently on, they will initialize to off the first time you run the program.
$ sudo ./awshome.py
Turning table-lamp OFF using code 283964
Turning floor-lamp OFF using code 284108
Listening...
Now we can navigate to the web interface and test updating the state, simply click on one of your things and Update Shadow with some new desired state:
Viola! Whatever was connected to your associated thing just turned on! Editing JSON is definitely not the easiest way to turn on your light however, let's make it easier!
Create a Lambda HandlerWe'll be using a Lambda Handler to not only tell Alexa what devices we have, but allow Alexa to control them!
Navigate to the Lambda Console and Get Started Now. We can Skip selecting a blueprint since there isn't a good one for a Python Home Skill, and we can skip Next on the triggers screen because we'll set that up later. You're now ready to start writing some code:
I've already started the code here (adapted and updated from the Alexa documentation site), you just need to make some small updates in the discovery section on Lines 33-60, highlighted here and copied below. Simply update each applianceId
with what you named your things, and give it a friendlyName
(that's what you'll be calling it when speaking to Alexa) and friendlyDescription
(that's what the Alexa app will display) You can add more or remove some if needed.
{
'applianceId': 'table-lamp',
'friendlyName': 'Table Lamp',
'friendlyDescription': 'The table lamp controlled by Raspberry Pi and RF switch 1',
'actions': [
'turnOn',
'turnOff'
],
'additionalApplianceDetails': {},
'isReachable': True,
'manufacturerName': 'AWShome',
'modelName': '1',
'version': '1'
},
{
'applianceId': 'floor-lamp',
'friendlyName': 'Floor Lamp',
'friendlyDescription': 'The floor lamp controlled by Raspberry Pi and RF switch 2',
'actions': [
'turnOff'
],
'additionalApplianceDetails': {},
'isReachable': True,
'manufacturerName': 'AWShome',
'modelName': '1',
'version': '1'
}
In order to allow our Lambda to change our IoT shadows, we need to give it special permissions by selecting Create a custom role
from the Role
dropdown, which will create a popup:
Give it a better Role Name and we can replace the given policy document with the one below, and click Allow:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": "iot:UpdateThingShadow",
"Resource": "*"
}
]
}
Once it's returned to the original screen we can finally hit Next and Create function.
Test the Lambda HandlerLambda lets us send test events, I've adopted the template to an event you can use below, just update the applianceId
and play around switching name
between TurnOnRequest
and TurnOffRequest
:
{
"header": {
"messageId": "01ebf625-0b89-4c4d-b3aa-32340e894688",
"name": "TurnOffRequest",
"namespace": "Alexa.ConnectedHome.Control",
"payloadVersion": "2"
},
"payload": {
"accessToken": "sampleAccessToken",
"appliance": {
"applianceId": "floor-lamp"
}
}
}
You're now controlling your lights using Lambda, but we're still editing JSON! Let's finally connect it to Alexa, but we will need the Lambda's ARN from this page, and we'll need to come back to it later so leave it open.
Home skills are different from normal Alexa Skills since they require authentication, so there's a couple of more steps, but to start we login with the same AWS credentials, then register and Add a New Skill from the Alexa Skills List.
Be sure you select Smart Home Skills API and give it a Name before clicking Next.
We get to skip the next step because Home Skills come with built-in voice UIs!
The first configuration field is easy, just enter the Lambda ARN we got from the last step. For the remaining fields, we'll be using Login with Amazon (open it in another window) to make the Authentication part easier since all Alexa users will have an Amazon account anyway!
First click Create a New Security Profile and then fill in some basic info (it's not too important since you won't be publishing the skill) and click Save:
Once the profile has been created click the gear icon and we'll need to synchronize some information from Login with Amazon (LWA) to Alexa, and vice-versa. I'll put the fields in list form and then in picture form:
- LWA Client ID to Alexa Client ID
- LWA Client Secret to Alexa Client Secret
- LWA Client ID to Alexa Client ID
- LWA Consent Privacy Notice URL to Alexa Privacy Policy URL (really either can be any URL)
- Go to the LWA Web Settings tab and click Edit
- Add https://amazon.com Allowed Origins
- Alexa Redirect URL to Allowed Return URLs
- Click Save on the LWA Web Settings tab
And finally on the Alexa screen
- Add https://www.amazon.com/ap/oa to Authorization URL
- Add profile:user_id to Scope
- Add https://api.amazon.com/auth/o2/token to Access Token URI
Step by step photos:
Finally we can click Next on the Alexa Configuration tab and return to the Alexa Skill Information tab where we'll copy the Application Id.
Back at the Lambda console we can go to the Triggers tab and Add trigger for the Alexa Smart Home skill pasting the Application Id we copied earlier and hitting Submit.
Alexa will now send Smart Home requests for your skill to Lambda!
Configuring the Alexa Smartphone AppYou can now enable your skill in the Alexa App. It shows up under Skills > Your Skills and once you're authenticated you should automatically Discover Devices to find your things! You can even group some of your things into a group!
Using an Echo or a simulator like Echosim.io you now tell Alexa things like:
- Alexa, turn on floor lamp
- Alexa, turn off floor lamp
- Alexa, turn on both lamps (assuming you created a group called "both lamps")
That's AWSHOME!
Wrapping Up: Autostarting at BootIf you'd like to make sure the service starts up automatically, I've included a startup script that can be enabled with two commands:
~/AWShome $ sudo cp awshome /etc/init.d/
~/AWShome $ sudo update-rc.d awshome defaults
You can also use Linux service commands like sudo service awshome start
, sudo service awshome start
, and sudo service awshome status
!
In just a couple of hours you have 5 fully customizable voice-controlled outlets for about $50! The range should be about the range of Bluetooth, but you can add an antenna to your transmitter, or get a bigger one, if you need more range.
The steps with IoT and Login with Amazon maybe seemed a little long and complicated, but what isn't immediately obvious is how scalable everything is. The same architecture we built, could scale to millions of customers and devices thanks to the power of AWS and the Raspberry Pi!
Advanced: Always Listening Alexa on the same Raspberry Pi!The Raspberry Pi is a little too overpowered to just be sending out RF signals! We can actually put Alexa on the device itself! This step requires more parts, and has some real headache points, so consider yourself warned!
Wiring up the ComponentsMicrophone/Speaker
You'll need a speaker plugged into the Raspberry Pi's 3.5mm port as well as a USB microphone (the PS3 Eye is only $5 on Prime!). You could also use a Bluetooth microphone/speaker if you have a bluetooth dongle.
Push Button
Normally for Raspberry Pi Alexa's you'll also need a push-button, but since this one is voice activated, you don't! I'll still include the wiring for it in case you want to have one anyway.
Status LEDs
The same goes for two status LEDs, one marks when Alexa is listening (I used Red), and the other marks when it's speaking/thinking (I used Yellow). They're definitely helpful, but not vital to make everything work. The LEDs also require a compatible resistor (my LEDS used a 330Ω one).
Diagrams
Installing AlexaPi
The sound stuff is a little trickier so everything will be done as root, normally it's not a good idea but it helps speed things up here.
~ $ sudo bash
/home/pi# cd ~
~# git clone https://github.com/maso27/AlexaPi.git
~# cd AlexaPi/
~/AlexaPi# ./setup.sh
The setup will ask you two questions about AirPlay and always-on-monitoring, both of these are optional and up to you. Installing everything will take quite some time, ~20 minutes for me! Thankfully, while it's going you can work on the Alexa portion.
Create the Alexa Voice ServiceFrom the Alexa Voice Service section of the dashboard select to Register a Product Type of Device:
Fill out the next fields however you wish, but remember its Device Type ID for later:
Select to Create a New Profile on the Security Profile step:
And fill the fields however you like:
Once created you'll have the 4 remaining additional fields you'll need to complete the Raspberry Pi setup displayed:
Once the setup has completed you'll be prompted for the information displayed:
Enter your Device Type ID:
awshome
Enter your Security Profile Description:
AWShome
Enter your Security Profile ID:
amzn1.application.8087e49d669441c3901d89bf89988099
Enter your Client ID:
amzn1.application-oa2-client.17e25b36240f4396a12361d751c63ab5
Enter your Client Secret:
9d1585673ec03cce319d594d0481ac20f5fdd44835ee4f93d4cb631a755a7b49
Ready goto http://10.10.10.74:5050 or http://localhost:5050 to begin the auth process
Before you navigate to the URL provided, we'll need to finish the AVS setup to ensure it knows about that URL. Switch to the Web Settings tab and enter the first URL in the Allowed Origins input, repeating it in the Allowed Return URLs input with /code
added to the end and click Next.
The Device Details step can be completed however you wish.
Same with the Amazon Music step.
Once the skill is created you can now navigate to the URL in a web browser connected to the same network as the Raspberry Pi. After a login process you will be given the success page.
Once you've reached that page you can kill the process on the Pi by pressing Ctrl and C together. Before rebooting you can test the service:
~/AlexaPi# python main.py
Checking Internet Connection...
Connection OK
You should hear "hello" from the speaker, and you can invoke Alexa by saying "Alexa" or by pressing the button and speaking. Here's a demo (pardon my crowded breadboard!):
It's definitely not as fast or as accurate as the actual Echo, but for a budget version it's pretty... AWShome!
Interaction DiagramBecause the project leverages home skills, it uses the intuitive built-in Voice UI, but the rough flow for the project is useful to view as a diagram:
Comments