Utilizing Siri and the Raspberry Pi to Unlock Home Automation

Posted by Renato Recio on October 24, 2015

Home Automation Part One:
Use Siri to communicate voice commands to your Raspberry Pi.


This is Part One of a multi-part series for creating a Home Automation system.

After some extensive searching on ways to use Siri to control the Raspberry Pi, I couldn't find any method that worked. Siri Proxy was the closest thing, but it a) no longer works in iOS7, and b) would still require you to be connected to WiFi, thus you couldn't connect through your cellular network. Also, there are apps out there like Home Remote, but that requires you to have an internet-connected device like WeMo or Hue. These are really cool products, but I just didn't want to spend $50 per light bulb or power switch. And plus, it always feels good to build your own, cheaper version of something expensive from scratch. So to get away from the more expensive solutions, I decided to go a different route by exploring what commands Siri had to offer that I could work with, and eventually I found a solution that was a lot easier than expected...

Let's look at a few Siri commands...

1) Email RaspberryPi@Gmail.com to turn on the lights
2) Text 555-RaspberryPiSMS to turn on the lights
3) Search Google to turn on the lights
Here we have three commands, each of which can potentially be used to be intercepted by the Raspberry Pi. Also, note that the third one is a use case for something similar to Siri Proxy, where you would use a proxy server to intercept the Google search query and then route that string to a Raspberry Pi program. However, it appears that no longer works, and like mentioned before, you would require a WiFi connection any time you wanted to send a command. There are ways we could make the other two work, but the problem with those is that they require you to tell Siri to "confirm" to send a message after Siri processes the first request. We want something simple that requires one quick command and that's it, so these are all not ideal. After some more searching, I saw a very simple command that caught my attention...
4) Note turn lights on
Note that the "turn lights on" was the command we created, we could have also said:
Note Let there be light!
Note Turn off the living room lights
Note Play that funky music!
The point here is, we now have an outlet to generate any command we want. So by prefixing your Siri commands with "note," Siri will instantly create a note with a command for you, which you can configure to do whatever you want.

Ok, now how does that help us actually read it from our RPi? Well, it turns out that iOS has the option to route all of your notes directly to an IMAP folder in your configured email account. All you would need is a Gmail account (you can make it specific for this app), and then just go to settings in your iPhone and enable Notes to synchronize to this email account. With these settings enabled, Siri will instantly send an email containing the full contents of that Note directly to your email account.

So to show how it works...we tell Siri "Note turn on lights" :

And after our command...

Perfect! Now we have a simple way to communicate a message from Siri to a location that is accessible from our Pi. One neat thing about this is that we don't have to configure port forwarding rules and allow any inbound connections from the internet for this to work, which we would have had to do if we made this a custom API instead.

Now what we are going to do is make a simple Python script that will read your email and await new commands. This will eventually be the driver that we will use to accept voice commands that will be used to automate your home.

In our Python script, the first function we are going to implement contains a loop that runs infinitely to check our email connection every other second for any recent Siri commands.

Here is our main() function:
def main(username, password):
    mail = imaplib.IMAP4_SSL('imap.gmail.com', 993)
    mail.login(username, password)
    while True:
        try:
            command = fetch_siri_command(mail)
            if command:
                execute_command(command)
        except Exception as exc:
            print("Received an exception while running: {exc}"
                  "\nRestarting...".format(**locals()))
        time.sleep(1)

Here we have a functional driver for our program. For a more fool-proof design, we could configure Supervisor to automatically run our script in the case of power outage or system failure, and we could handle lost connections by re-instantiating the mail connection if there are Exceptions or Timeouts. But for a simple and functional program, this will suffice. That said, we now have a simple main function that will act as our driver for the program. To use this, make sure to pass in the Gmail username and password that you configured for your Notes Gmail account.

Next thing we want is a function that can fetch the latest email id, and if it hasn't been processed yet, we will fetch its contents and return them.

Here is how we will implement our fetch_siri_command() function:
last_checked = -1

def fetch_siri_command(mail):
    global last_checked
    mail.list()
    mail.select("Notes")
    result, uidlist = mail.search(None, "ALL")
    latest_email_id = uidlist[0].split()[-1]
    if latest_email_id == last_checked:
        return
    last_checked = latest_email_id
    result, data = mail.fetch(latest_email_id, "(RFC822)")
    voice_command = email.message_from_string(data[0][1])
    return voice_command.strip().lower()

That was pretty easy! In less than 15 lines of code, we have a fully functional hack that can fetch Siri commands. The only thing we have left is our execute_command function, which we will implement later after we learn how to communicate with other things, such as power switches, light bulbs, and our stereo system.

All in all, the minimal effort to implement this solution is well worth the time, considering that we can use the full potential of Siri's voice processing capabilities and at the same time use our Pi as a server that doesn't require a public facing API.

If you are interested in learning how to use these commands on your RPi, check out some of my other blogs. I hope this was helpful, and if you have any questions, suggestions for improvement, or alternate Siri hacks, comment below!

Click here to find relevant file(s) for this tutorial.


Thanks for reading :)