When I first heard about this contest, I was a little leery of it. I didn't have any problems with the actual contest, but I didn't want to be a part of it, because the end product would increase the amount of control that a large corporation had over things that are inside of my house. I have come to terms with that, however, once my kids got very excited about the idea, and because of the silly, just for fun idea that we had about what to do.
When we moved into our house, we found an old air siren/horn (I'm not actually sure which) up in the corner above our front door. With the vaulted ceilings, this ends up being about 12 feet in the air, but it's pointed down towards the door. It must have been used as part of an alarm system at one time, but the wires for it disappear into the wall. I've used a circuit tone tracer to follow them somewhat, but they seem to just stop randomly inside the wall. I think that there was a security panel at one point there, but it's been removed or just covered over with sheetrock.
So the idea is to control the air siren with the Arduino and a relay to a power supply. I'm assuming that the siren is run on 12 volts DC, just because the only air sirens I've ever seen were that way, but I haven't seen very many, so I'm not sure of that. But no matter, I have plenty of old power supplies with various outputs, so I can probably find one that will work. Worst case, I pick up a new one. We want to be able to tell Alexa to "repel intruders" when solicitors come to the door. (We have a 'No Soliciting' sign, but it's only partially effective. There are plenty of people who ignore it.) Possibly also it would be fun to ask Alexa to "make some noise" and have her run it. Running them for different lengths can have very fun different sounds, so maybe be able to have it have a couple different patterns for different things. (For example, cycle the relay on for a few seconds, then off for a few vs. on for half a second then off for a couple then back on for half, etc. That would have to be determined just by playing with it to see what settings sound best.)
My first thought was to absolutely minimize the hardware that would be running. I would rather not have multiple servers sitting in between Amazon and my house doing various 'translations' - in which category I also include the idea of having a separate computer or Raspberry Pi board running just to allow communications from one end to the other. I also saw that there were 'bonus points' for using the Zigbee smart hub in the Echo Plus, and that just sealed the deal for me. (Because really, if I'm going to go to the effort to get this set up and type up everything for the contest, I might as well go all in and get as many points as I can.)
So my initial plan was to have an Xbee from Digi running on an Arduino to handle the radio portion. This looks like it would work okay, as long as I keep to the very limited interactions that Amazon so far supports on the smart hub. After many hours of scouring through documentation and trying to figure out the API for the smart hub IP side, I finally realized that it simply wasn't possible. Amazon has not yet released a way to communicate with the devices that are connected to the smart hub, other than their very limited set. (They support turn on and turn off, so I can do the basics through them, but I'm not allowed to send any custom messages to allow more complicated behavior and increased choices for people.) This then drove me to change plans a little.
The Xbee plan was going to end up with a device with limited options, so I then thought about having two variants. Plus the Zigbee connection to any Home Automation device has very seldom been done. The only one published I could find was one that was built on a Parallax Propeller board. They are different enough that it twisted my mind understanding how the code works. One thing to know is that they are massively parallel in their processing for an embedded chip. They have eight cores, and each one can be running independent code, so you don't have to worry about a serial port bogging you down or missing characters, for example. So now instead of just doing the Xbee option, I will also program an option for the Arduino MKR1000, which has a built-in WiFi module, which will then act as a 'Thing Shadow,' as demonstrated in the example project, 'Alexa Controlled LEDs Through Arduino Yún.' This way I would have the option of sending the board whatever I wanted from my Lambda code, so that I could change the siren patterns and even send an intensity modifier for PWM on the output.
Well, things didn't go according to plan, yet again. I found out that the MKR1000 just didn't have enough power to do the SSL security layers for interfacing with Amazon. It has enough for a lower security level, like some of the IFTTT servers, or if a MQTT server has a low enough standard, but I really didn't want to be running another server in between. Eventually when I have enough of the smart home things set up around the house I probably will end up getting my own home automation server of some kind to sit here and watch everything, but I'm not even close to there yet. So I decided that the simplest overall would be to go with the Arduino Yun, since it has the Linux coprocessor and can handle all the heavy lifting, while being a tiny form factor and very power efficient.
Additionally, I'm having a heck of a time getting the Xbee to communicate with the Echo smart hub. I've been beating my head against the wall trying to find out why the smart hub is not answering back like I expect it to. Part of the problem is that there's so MUCH documentation on the protocol, but very little to none about exactly what the Echo will do, or what it's waiting for. It also doesn't help that parts of Xbee's documents can confuse you when looking at Zigbee's documents. (Digi decided to reverse the order of the bits in a byte that you send to it. I guess they decided that little-endian was too confusing and they have their chip internally flipping the bits around. So Zigbee says that they have to be little endian, but you have to give them to the Xbee big endian.) Took some comparing of very large documents and then also using a packet sniffer to see what was actually being transmitted to convince myself I understood what was going on with that one. So the final plan is going to leave out the Xbee until a later project.
This was far harder than I expected it to be. Just needing to have the voice recognition be done in the cloud increased the difficulty beyond what I had planned on. In retrospect, it makes sense, because there need to be so many layers of security on all of the communications, just to make sure that everything is as safe as possible. This was also my first contest, so that also had an impact on how much I knew to expect. I mean look at this picture. I'm starting to get the hang of understanding some parts of it, but others are still mysterious enough that I'm not sure where my code is failing me on the Zigbee protocol.
I was sure that between having a sniffer and being able to send out whatever random packets I wanted to from the Xbee that I would be able to figure out the magic incantations to get the hub to talk to me, but nothing worked. (Well, that's not entirely true. The hub let me join the network, but that was the extent of it. There are definitely packets going back and forth, but so far the hub must be getting very confused by something I'm sending or not sending.
I had a software serial port spitting out info straight from the code while also sniffing what went over the air, and I still haven't gotten it yet. Though I haven't actually given up yet, it's just that I've run out of time for this contest and have to put it off until next time. Going in, I figured that it was straightforward enough that there would be hundreds of variations of people connecting Xbees to home automation of various sorts. Years ago the Xbee was really a main choice for hobbyists doing wireless, so I thought that their use would have only grown. Though it makes sense, with all of the competitors' boards that can do a lot and are sometimes a good bit cheaper. I had NO idea I was wading into thousands of pages of documentation without enough of a trail blazed ahead of me for it to be feasible in the time I allowed myself.
I ended up going with the 'Thing Shadow' service running with an Arduino Yun, as seen in plan 3, above. I'm a big fan of reducing the number of computers in the path, so the idea of having a 'Shadow Thing' was great. I LOVE the idea of being able to simply poll for updates instead of having multiple different 3rd party serves involved in the process. This way once the Amazon settings are made and the Alexa Skill is programmed then everything will work without further computers or modifications. At least the steps in the process of building this will look very similar to Ben's project, because I want to recreate the same process he used to create a shadow service, even though I want to extend it.
Step 1) Create an Amazon Developer Account (if you don't already have one.)
Go here and set up your account. Amazon tries to be very friendly and hold your hand through the process if you need to create a new account. There are plenty of help sections and 'how-to' articles to help at every step through the process. I won't repeat all that information here.
Step 2) Setup LWA (Login With Amazon), Create Lambda skill, and Create Smart Home Skill
This really feels like a few steps in one, and if I were to describe how to do all of them, I would definitely split it out, but the whole thing is described very throughly in the link below, which is put out by Amazon, and hopefully also kept accurate and up-to-date as time goes by. So for the purposes of this project, this is just one step.
In following this '15 minute' guide, I spent quite a few hours troubleshooting. For some reason the provided example python code that is on the github page doesn't quite work with the Amazon service. I had to comment out the v3 json validation, since it kept complaining that it couldn't import the 'validate' module. I think they might have something wrong with their configuration (or else I'm just not good enough with code to get it right, but I AM following their guide to the letter.) This is the error message from Amazon's CloudWatch error logs:
Unable to import module 'lambda': cannot import name 'validate'
Step 3) Set Up Amazon Internet of Things 'Thing'
This is the connecting server that handles the communication and translation between the Arduino and Alexa. Basically it just sits there and is a 'simple' web server. When Alexa wants to find out something or change it, she will either read or write to the IoT server, respectively. Then the Arduino will poll the server to find out if anything has changed. This can happen at a maximum of once per second, according to Amazon's terms, and for anything like this that should be responsive to users' voices, it really shouldn't be any more than that. If the Arduino is passing any messages back to Alexa, then this is also how it would do that. It really is a very simple overall method that doesn't require a server to be running on the Arduino, which of course simplifies the code and burden on that little processor. In addition, it doesn't require users to create any holes in their firewall to implement it, since it's just pulling web pages, in essence, which every firewall should allow, and if not then there are bigger problems than worrying about home automation. Some people have set up a personal MQTT (Message Queuing Telemetry Transport) server with a Raspberry Pi or similar on their own network, but this way Amazon handles everything. (Their IoT server uses MQTT, so you get a lot of functionality.)
The instructions for setting up the server for the Amazon IoT service are here. That is really a pretty good guide, but there are some points where it is now out of date and I had to look a bit. I'll include here screenshots and instructions for the parts that are different.
First, he says to 'Click on create a resource' but for a stretch there his instructions and the screen captures are wrong. So use these:
Click on the 'AWS IoT' symbol and words:
Here you can really click on either thing. This is just information about how the system works. It will keep coming back if you ignore it, though.
Then you get to this page, where you click on 'Register a Thing'.
On this page, click 'Register a Single Thing' since we are only making one of these. If you want to make more, that's great, but I didn't go that way. I believe that's more for companies that are putting out many of these at once.
Here you only need to enter in the name of the Thing. The other selections would be useful if you have a bunch of them and need a good way to find them later, but at least for now I'm not going to bother. (This is my first.)
You will need to click on 'Create a Certificate' in order to get the encryption data that is needed for securing your connection and hooking up to the IoT server.
Now you need to download your certificates/keys for the access. Pay attention here - you can never download the keys once you leave the page, as a security measure. You need to keep them safe. (Of course, you should always be able to generate a new pair if needed, but these ones would then be deactivated.) Press on the 'Activate' button, which will then change to be a 'Deactivate' button, but don't push on that.
Next, push on the 'Policy' button. This confused me for a while. Based on how Amazon has their security set up, everything is attached to a certificate. So if you want to allow a device to do anything, and it is using this certificate (and associated encryption keys) then you need to set the policy that is connected to this certificate to enable that. You can have as many policies attached to a certificate as you want, it's very flexible that way. You can also have the same policy attached to many certificates, so if you have a group of 'Things' they can all have the same policy, in order to make administration easier, I expect. Also, this is a certificate that I've since erased, so I didn't care that it shows all of the name.
In the oudated guide, he also wants you to get the REST endpoint for the device. This isn't available yet. Once you are done with the certificate completely, you click on the 'Thing' (in my case 'Siren') then on the next page there are links to choose to see the various endpoints that we will use.
Here you have the selections for getting the different connections. Under 'Interact' on the left hand side is where you see the REST endpoint, for example. There are also a bunch of MQTT addresses shown on that page.
Then continue with the setup tutorial, except don't do the part in this page where he talks about adding code to the top of the lambda to connect to the Shadow Thing service. We're going to instead use boto3 like was done by Ben in his tutorial that was already mentioned above, but he never really talked about the boto3 specifics. (Either that or it was buried so deep that I managed to miss it.) Boto3 is an easy-to-use python library specifically for working with AWS, and it's pre-installed within Lambda so all you need to do is add the 'include' at the top of the lambda code, and you can work with it. It's already in the code on my github.
I had a heck of a time managing the final connection between the Lambda service and the Shadow Thing service. My hang up was in misunderstanding the AWS IAM service and how to get it set up to allow the two to communicate. Basically I needed to attach the AWSIoTFullAccess policy at the IAM console. It might not be as safe as having a more locked down setup, but since this is just for my own purposes, and has encrypted communications, I'm not going to worry about locking it down more. This also ties into my mention of the policies and certificates. In order for this to work, you also need to tie a 'User' to a 'Policy.' (Roles are like groups, and allow you to set up/change whole sets of things at once.)
At this point things are getting pretty close to ready to work with the Arduino. We have a connection between almost everything in Amazon's cloud, so now it's time to turn our attention to the Arduino.
This part was quite a challenge at first. Turns out the firmware on my Yun was old enough that it didn't quite match the description of what other people were seeing. The white light is supposed to be lit on the Yun when it's finished booting, but mine never came on. Turns out that was because of the old firmware. I got it upgraded finally, but mine was so old that even the instructions (see the section on using the command line) were not quite accurate for it. I finally issued the commands on the Yun command line to do the upgrade, and that worked well. Part of the reason for the confusion is that the new file I got from Arduino had a few extra letters in the filename, so I just had to adjust that. But maybe that's why the automatic tool didn't do anything with it?
In order to load the project to the board, there's excellent readme info included in the zip file. The file comes from Amazon's github, but just to ensure that I always have the exact files that worked for me, I also included a copy of everything on my github with this project. There are some steps that took a little figuring out. The script is run on your computer.
When first setting up the password, it worked best for me to type it into a text document and then copy and paste it into the field. There's no 'see it for a second before it disappears' as you type each character like many systems use. There's no way to see it, so you might as well do it this way. I had to reset the wifi module a couple times because I messed up the password, and each time you do it you have to wait for another minute or two for it to be ready to log on again. It feels more like 5 or 10 when you're stuck at a point on your project waiting just for that... :)
As far as resetting the wifi module, that's by holding down the wifi reset button for somewhere between 5 and 30 seconds. Be VERY careful about getting close to 30, though, because if you hit that magic number then the WHOLE board gets reset back to factory blank conditions. I actually had to do that, because the install script that came with the files kind of messed things up. First it filled up my home directory, and then it failed on installing pip for python. I moved everything over to the SD card and mounted it in place of my home directory, but that still didn't work.
After resetting the whole board, thinking that the script might have altered something else, I went ahead and mounted my SD card to the home folder of root like this:
First log in to the board: This is on linux.
ssh root@<board ip address>
Finally I had to figure out how to bypass the failure of easy_install to put pip on the drive. I found this page that says to do this:
wget https://pypi.python.org/packages/source/p/pip/pip-6.0.8.tar.gz#md5=2332e6f97e75ded3bddde0ced01dbda3\ --no-check-certificate easy_install pip-6.0.8.tar.gz
It's a little bit older version of pip, but when I tried to get the newest, it wouldn't do it without having a secure connection. (The server is refusing.) I don't need the newest version for this, so it worked. It takes a while to build and install it once it's been downloaded, but just wait for it.
Afterwards, you could just re-run the script again, but after reading through it, there's only one more thing that it tries to do. I just ran this from the command line: (While still logged into the board through SSH as before.)
pip install AWSIoTPythonSDK==1.0.0
This installs much quicker than pip itself. (Before my firmware was updated, this step took forever. I don't know what it was hung up on, but I left it running for hours before it was my bedtime, and it was still going when I got up in the morning. At least 10 hours overall. Make sure to have the updated openWRT firmware!)
Finally, when running that last command, pip helpfully reported that it was not the latest version, and how to upgrade itself. I figured it couldn't hurt, and ran the command, and this was a mistake!! The install made it enough of the way through to uninstall the old version of pip without installing the new one, and suddenly ran out of room on the device, so the process quit, and then left me without a working pip on my Arduino, and no space to re-run the command above with easy_install... I had to wipe out the pip directories under the directory /usr/lib/python2.7/site-packages (There were two with pip in the name.) just use rm -rf pip* Then reinstalling still didn't work, because something in the system was too big. At that point I moved things around and put more stuff on the SD card to make it work. This slows things down, though. Long story short, let this be a warning, and don't try to upgrade pip! (Though, I'm not sure I really need it on there now that I have the AWS drivers loaded...)
Another issue that came up is for some reason on my Yun, there was no openssl installed. This kept causing errors in the connection to the AWS servers, of course, because it simply couldn't authenticate itself without having openssl to do the interpreting. I had to run this from the command line of the Arduino in order to get openssl, and then it was happy.
opkg install openssl-util
I see a few areas for improvement in the future.
- Make the AWS MQTT library for the Arduino Yun non-blocking. It's great that it's even available, but most of the hard work is passed off to the Linux co-processor, so there's really no excuse to have to spend most of it's time blocked and just waiting for input from the other processor.
- If the MQTT library was non-blocking, this would open up the possibility of having a much shorter and more regular cycling of the siren. And an even further improvement would be running it off of a MOSFET to then be able to use PWM and have variable power. (That wouldn't be as necessary with this, since the spinning of the siren to make noise has such a HUGE time constant. But I'm thinking of being able to adapt this work to control many other devices.)
- Finish work on the Zigbee/Xbee integration with the smart hub so that we can with that directly from Arduino. This is a very lightweight workload for the Arduino, since the Xbee handles so much of the communications stack and provides a relatively lightweight standard. (Lightweight as far as what the Arduino has to do, not so much in figuring out just how to program it...)
The schematic is super simple, of course. I just wired up the output of the Yun to a relay board that has optically isolated inputs to have the least load possible on the Yun. You can use any output pin you would like, but then just alter in the code which one you want it to control. (Or more than one, if there are other things you also want it to do.)