Build

Build a Voice Controlled Outlet with Raspberry Pi and Swift

8 min read Michael Carroll on Aug 17, 2016

Ever wish you could control all of your electronics with a simple command, or just the push of a button? Well, armed with a Raspberry Pi, a smart phone, and PubNub’s Global Data Stream Network, you can make that dream a reality. Get ready to use your smart phone to be able to control outlets in your house from anywhere in the world.

In this tutorial, I’ll show you how to use a Raspberry Pi to control a power outlet using an RF transmitter, a process facilitated by commands sent via PubNub. Then, I’ll show you how to build a very simple app using Swift, Apple’s programming language, to send those commands with either your voice or the press of a button. This tutorial will assume you’ve already set up your Raspberry Pi with Raspbian or a comparable operating system. If you haven’t, no worries, just check out the first section of this tutorial on creating a Raspberry Pi Smart Home entitled “Setting Up the Raspberry Pi” and you’ll be brought up to speed.

 

Outlet Control App Screenshots

Required Hardware

RF Transmissions

In this project you’re going to use an RF Transmitter to send codes to an Etekcity outlet, a job that was previously done by a remote. This process requires wiring the transmitter and the receiver to the Raspberry Pi, finding the codes the remote uses, and transmitting those codes to control the outlet without the remote.

Hardware Setup

Wired RF Transmitter and Receiver
Wiring the transmitter and receiver is a fairly simple process. On the transmitter (the component with 3 pins), connect DATA to GPIO 17, VCC to 5V, and GND to Ground. On the receiver (the component with 4 pins), the left pin, when viewed face-up with the pins facing down, should be connected to 5V, the second pin from the left to GPIO 21, and the right pin to Ground. You’re ready to start using it!

Using RFSniffer

To figure out the codes that you need to send, you first need to install WiringPi. Navigate to the command line on your Raspberry Pi and download the software using git.
$ sudo apt-get install git
$ git clone git://git.drogon.net/wiringPi

To finish the installation, type the following commands.

$ cd wiringPi
$ ./build

To make sure it worked, type gpio -v into the command line, and you should see details about your Raspberry Pi printed to the console. To use RFSniffer, type the following command.
$ sudo /var/www/rfoutlet/RFSniffter
Now when you press buttons on the remote that came with the outlet, you should see numbers appear on the console. Record the five-digit numbers that appear when you press off and on – you’ll need them to toggle the outlet.

Testing the Codes

To make sure your RF Transmitter is working properly, try turning the outlet on and off using the command line. Just type the code below, replacing [code] with either of your five-digit numbers.
$ sudo /var/www/rfoutlet/codesend [code]
If the light on the outlet turned on and off based on your commands, congratulations! You’re right on track. If not, you’ll need to go back and make sure everything is properly installed, then try again.

The Raspberry Pi Script

Now that you know your RF transmissions are working properly, it’s time to write a Python script to send the codes for you, based on messages that will be sent using PubNub.

Script Setup

Before you can start coding with PubNub, you’ll need to make sure all the libraries you need are installed and up to date. Open up your terminal by clicking on the black icon in the top left corner of your screen, then type the following commands to update and install the necessary libraries.
sudo apt-get update
sudo apt-get install python-dev python-pip
sudo pip install pubnub

Then, at the top of your script, include the necessary libraries.

import os
import sys
from pubnub import Pubnub

Finally, to initialize PubNub, just input your publish and subscribe keys and define your channel.

pubnub = Pubnub(publish_key='your-publish-key', subscribe_key='your-subscribe-key')
channel = 'OutletControl'

Receiving PubNub Commands

To receive commands from PubNub, you first need to subscribe to your channel and define your callback and error functions.

def _callback(m, channel):
def _error(m):
    print (m)
pubnub.subscribe(channels=channel, callback=_callback, error=_error)

Next you should fill in your callback function to react to PubNub messages by turning the light on or off.

def _callback(m, channel):
    if m.get("outlet") == "on":
        os.system('sudo /var/www/rfoutlet/codesend [code]')
    if m.get("outlet") == "off":
        os.system('sudo /var/www/rfoutlet/codesend [code]')

And you’re done with the Raspberry Pi part! Time to move on to creating the app.

Creating the App

Now that you’ve set up the Raspberry Pi, you’re ready to build an app to control it. In this tutorial I’m going to show you how to do it using Swift, but it can easily be adapted for many different programming languages or mobile devices, just take a look at all the PubNub SDKs and pick one! The syntax will be different, but all you really need is a subscribe call to make it work.

Installing PubNub and SpeechKit

To install both PubNub and SpeechKit, you’ll need to use CocoaPods. There’s a great tutorial on the CocoaPods website to install and get started with pods. After you install the software, just follow the directions under Creating a New Xcode Project with CocoaPods to begin your project. Your podfile should look like this when you’re done.

target 'Outlet Control' do
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod ‘PubNub’, '~> 4.4.1'
pod 'SpeechKit', '~> 2.1'
end

Initializing PubNub in Swift

To use PubNub, you’ll have to initialize it in the AppDelegate.swift file using your publish and subscribe keys.

class AppDelegate: UIResponder, UIApplicationDelegate, PNObjectEventListener {
var window: UIWindow?
var client : PubNub?
override init() {
let configuration = PNConfiguration(publishKey: "your-publish-key", subscribeKey: "your-subscribe-key")
client = PubNub.clientWithConfiguration(configuration)
super.init()
client?.addListener(self)
}
...

Building the User Interface

The UI for this project is fairly simple, though you’re free to add some more flair if you’d like. Swift App User InterfaceTo control the outlet, all you really need is a switch. I also included a button to use with Speechkit to that the outlet can be controlled using voice commands. To create the components, open Main.storyboard in Xcode. In the toolbar on the right side side of the screen, show the object library by clicking on its icon.
Drag a button and a switch onto the storyboard and label them appropriately. Customize the page to your liking using different colors, fonts, and spacing. Here’s a peek of my finished product.
Outlet Control App User Interface

Finally, you need to link your UI elements to your code. Make sure you’re using the assistant Xcode View Optionseditor by selecting the appropriate icon at the top of the page. You should have both Main.storyboard and ViewController.swift visible. In ViewController.swift, import UIKit, PubNub, and SpeechKit at the top of the program.

import UIKit
import PubNub
import SpeechKit

Hold the control key while you click the Listen button on your storyboard, then drag it to your ViewController class. Name the button, but don’t change any of the other settings. Do the same for your switch, so you can easily reference it later. Now control-drag the button and the switch again, but this time change Connection to Action. This will allow you to create functions that are only called when each button is pushed, which you’re now ready to do.

Using SpeechKit

Let’s start with the Listen button. You’ll want to be able to push it, say a command, and have the app interpret that command and send a corresponding message to your channel. This is actually pretty simple using SpeechKit from Nuance Developers. They give you all the functions you need, you just need to include them in your app and tweak them for your needs. First, you’ll need to create an account with Nuance. It’s easy to do through the Nuance website, plus it’s free!

Once you’ve got all your credentials settled, you need to define the delegate in the class header.

class ViewController: UIViewController, SKTransactionDelegate {
…
}

Now, in the ListenClicked function, define the session with your various tokens.

 @IBAction func ListenClicked(sender: AnyObject) {
            ListenButton.setTitle("Listening", forState: .Normal)
            let session = SKSession(URL: NSURL(string: "your-string"), appToken: "your-token")
            session.recognizeWithType(SKTransactionSpeechTypeDictation,
                                      detection: .Long,
                                      language: "eng-USA",
                                      delegate: self)
        }

Next you’ll need to create a transaction function inside of your ListenClicked function for SpeechKit to use to interpret speech. You can choose any keywords you like to control the outlets, but I chose “off” and “on” for simplicity.

func transaction(transaction: SKTransaction!, didReceiveRecognition recognition: SKRecognition!) {
        if recognition.text.lowercaseString.rangeOfString("on") != nil {
             print("Found \"on\" in speech")
        }
        if recognition.text.lowercaseString.rangeOfString("off") != nil {
            print("Found \"off\" in speech")
        }   
}

Now when you click the Listen button in your app, you’ll see a message on the console when you say “off” or “on.”

Sending PubNub Messages

It’s time to start streaming information between the Raspberry Pi and the app using PubNub. To do this, you just have to publish messages to your channel when either the switch is pressed or SpeechKit detects your commands. First you’ll need to link your initialization in AppDelegate to ViewController.
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
Next, write publish functions that correspond to pressing the switch.

 @IBAction func Switch(sender: AnyObject) {
        if OnOffSwitch.on {
            appDelegate.client?.publish(["outlet":"on"], toChannel: "OutletControl",
                                        compressed: false, withCompletion:{(status)->Void in
                                            if !status.error {
                                            }
                                            else{
                                                print("Publishing Error (On)")
                                            }
            })
        }
        
        else {
            appDelegate.client?.publish(["outlet":"off"], toChannel: "OutletControl",
                                        compressed: false, withCompletion:{(status)->Void in
                                            if !status.error {
                                            }
                                            else{
                                                print("Publishing Error (Off)")
                                            }
            })
        }
    }

Now just put a publish function in the “if” statements you made for the Listen button and you’re good to go!

Testing the Setup

To test your app and Raspberry Pi setup, make sure your script is running on the Raspberry Pi, and upload the app to your favorite mobile device. You should be able to toggle your outlet on and off by using either the switch, or by pressing Listen and saying either “off” or “on.” Ta-da! Now you can control the outlet from anywhere, with just your voice or the simple tap of a button.

Next Steps

Congratulations! You’ve successfully put together an outlet that can be controlled remotely from your phone. Hopefully you’ve also learned a little bit about Raspberry Pi, Swift, and PubNub along the way. Now you’re ready to tackle other projects using Swift, like this AppleTV controlled simulated Smart Home, or this real-time radio station. If you want to explore more with Raspberry Pi, check out these cool tutorials on building a heart rate monitor or a dashboard camera. Whatever you choose to do, have fun, and good luck!

0