Have you ever wanted to be able to control all the devices around you with just the the touch of a screen? Well, thanks to the ever growing Internet of Things, you're getting closer and closer to making that dream a reality. In this tutorial, you'll learn how to build a simulated “smart home” using a Raspberry Pi and an Apple TV. The first part of this endeavor, in true IoT style, is wiring all of the necessary hardware components, so that when you program your AppleTV you'll be able to control real devices. In Part 1, you’ll learn how to control an LED, a waterproof temperature sensor, and an 8×8 LED matrix to simulate turning on lights, boiling water, and adjusting the thermostat. In Part 2, we'll show you how to program an AppleTV to control all of these devices remotely, with just the touch of a finger. Using a Raspberry Pi, an AppleTV, and PubNub’s global network, you’ll be able to simulate the smart home of your dreams.
The full code repository is available on GitHub.
Hardware You'll Need
- 1 Raspberry Pi 2, Model B
- 1 USB keyboard
- 1 USB mouse
- 1 external monitor
- 1 HDMI cable
- 1 micro-SD card
- 1 micro-SD card adapter
- 1 2.5A power supply
- 1 USB WiFi dongle
- 1 breadboard
- 1 LED
- 1 330Ω resistor
- 1 4.7kΩ resistor
- 1 Waterproof DS18B20 Temperature Sensor
- 1 MAX7219 LED Dot Matrix
- Male/male jumper wires
- Male/female jumper wires
- Female/female jumper wires
Setting Up the Raspberry Pi
Before you can really get to work wiring all your hardware components, you need to set up your Raspberry Pi. If you already have Rasbpian or a comparable operating system running on your Pi, you can skip to the last step of this section, Installing and Updating Libraries. If you’re new to the wonderful world of Raspberry Pi, no worries! We’ll have you up and running in no time.
Formatting Your SD Card and Downloading NOOBS
The first step to using your Raspberry Pi is making sure that you have an operating system (OS) to work with. If you bought your Pi as part of a kit, your micro-SD card might already have this installed, so double check whether it’s blank before continuing. If you don’t have anything installed, there are a couple steps you need to complete. First, format your micro-SD card by installing SD Formatter 4.0 on your computer and plugging in your card with an adapter. After opening up the software, select your card and click Format as shown below.
Next, you’ll need to download NOOBS (New Out of Box Software) through the Raspberry Pi downloads page. Once you’ve unzipped the file, transfer all the files inside to your newly formatted micro-SD card. After the process has completed, safely remove the card and insert it into your Raspberry Pi. You’re ready to fire it up!
Booting Up Your Raspberry Pi
Plug your keyboard, mouse, monitor, WiFi dongle, and power supply into the Raspberry Pi. You should see a rainbow screen on your monitor, after which a raspberry will appear, followed by a screen to install Raspbian. Select the recommended version of Raspbian and press Install. Once you reach the screen that says Raspberry Pi Software Configuration Tool, press the right arrow twice to select <finish> , then press the Return key.
When the command line appears, if it asks for a login, type in pi and press Return. When it asks for a password, type raspberry. When the line that says pi@raspberrypi~$ appears, type in startx and press the Return key. The GUI should launch, and now you’re ready to go!
Connecting to WiFi
To connect your WiFi dongle to the internet, go to Menu > Preferences > WiFi Configuration. Press Scan to view available networks. Then, double click your network and enter the network password in the box labeled PSK. Click Add and you should connect to the network.
Getting Started with the Script
Now that your Pi is up and running, you’re ready to create your project. In order for your Smart Home to react to commands from the AppleTV app, you need to utilize PubNub’s global network to send messages between the app and the Raspberry Pi. After some initial setup, it only takes a couple lines of code to make it happen.
Creating Your Project
First, you’ll need to create a folder so that you can store all your project files in one place. Open the File Manager by clicking its icon in the toolbar at the top of the screen and navigate to the folder called Pi. The go to File > Create New… > Folder to create your directory. Give it a simple name, as you’ll have to refer to it in order to run your script. Next, you need to create your main script. Go to Menu > Accessories > Text Editor to open up a blank document, then save it to your folder as smarthome.py.
Updating and Installing Libraries and Drivers
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
Next, you need to install the driver you’ll need to operate your 8×8 LED matrix and microcontroller. Type in the following commands to install the MAX7219 driver.
git clone https://github.com/rm-hull/max7219.git
sudo python max7219/setup.py install
Then, open up File Manager again and move the contents of the newly installed folder to your Smart Home folder, so that the folder called max7219 is in the same folder as your script, and you’re good to go.
Starting Your Script
After opening up your script again, you’re ready to get started! This project requires a lot of different libraries, so before you begin make sure to import everything you need at the top of your code.
import RPi.GPIO as GPIO import os import glob import time import sys import max7219.led as led from pubnub import Pubnub
Also set the GPIO mode so that you refer to the pins by their GPIO number, just to minimize confusion.
GPIO.setmode (GPIO.BCM)
Initializing PubNub
To start using PubNub, initialize it using your publish and subscribe keys, as well as the name of the channel that you plan on using in your AppleTV app.
pubnub = Pubnub(publish_key='demo', subscribe_key='demo') channel = 'Smart_Home'
Next, you need to define callback and error functions, so that you can analyze the messages sent through PubNub. For now, the callback function is empty, but don’t worry, you’ll fill it in later. The last step is to place a subscribe call to receive the data, and you’re done! PubNub is all set up and ready to roll.
def _error(m): print(m) def _callback(m, channel): pubnub.subscribe(channels=channel, callback=_callback, error=_error)
Running Your Script
If at any point you want to run your script, to test the different parts of your code or to view your finished product, you need to open up your terminal and change the directory to the folder you created, as shown below. Then, type in the next command to run your Python script.
If you want, you can include print statements in your code so that you can log the activities of your Raspberry Pi in the terminal window, or you can use the PubNub Developer Console to monitor the channel. Either way, finding ways to visualize the output of your Raspberry Pi will be very useful when it comes to debugging.
Adding the Hardware
Now that you’ve set everything up, you’re ready to start connecting the hardware components of your project. You can do these in any order, just be sure to keep track of which GPIO pins you use for each component so as to avoid confusion later.
Controlling an LED
Let’s start with the LED. You’ll first need to put together the circuit, then edit your script so that the LED can be controlled remotely by your app via PubNub.
Putting Together the LED Circuit
The LED circuit is really, really simple, as you can tell from the picture above. All you need is an LED, a 330Ω resistor, a breadboard, and two male/male wires to put it together. Wire a GPIO pin and a Ground pin on your Raspberry Pi to the breadboard. Then, connect one end of your resistor to the Ground wire, and the other to the short leg of the LED. The long leg of the LED connects to the GPIO wire, and you’re done!
Controlling the LED through PubNub
For this project, you want to be able to turn the LED on and off using specific commands sent from the AppleTV to your PubNub channel. First, initialize the GPIO pin you used to connect the LED and specify the pinmode.
LED_PIN = 17 GPIO.setup(LED_PIN,GPIO.OUT)
Now it’s time to start filling in your PubNub callback function. You'll want the app to send the messages in the form of a dictionary with the key “light” and a value of either “off” or “on” so that they're easily decoded. You just have to search for the key and turn the light off or on based on its value. Easy!
def _callback(m, channel): if m.get("light") == "on": GPIO.output(LED_PIN, True) if m.get("light") == "off": GPIO.output(LED_PIN, False)
Reading a Waterproof Temperature Sensor
Next hurdle: attaching a sensor to measure the water temperature inside a kettle. Before you get started, you have to strip the ends of the DS18B20 to expose the wire underneath using either wire strippers or scissors. If you use scissors, it’s easy to accidently cut through the whole wire, so be careful!
Hooking Up the DS18B20 Sensor
To connect your sensor to the Pi, you’ll need to attach female/male wires from each of the three wires in the sensor to your breadboard – you might have to use tape to hold them together. Then, connect the row with the black wire to a Ground pin on your Pi. Attach a 4.7kΩ resistor between the rows with the red and yellow wires, then connect the end of the row with the red wire to 3.3v and the end of the row with the yellow wire to a GPIO pin.
Initializing the DS18B20 Sensor
To use this sensor in your script, you have to first alter your system folders to include the driver you need for the sensor.
os.system('modprobe w1-gpio') os.system('modprobe w1-therm') Base_dir = '/sys/bus/w1/devices/' Device_folder = glob.glob(base_dir + '28*')[0] Device_file = device_folder + '/w1_slave'
Next, to get the temperature data from the sensor, you need to access it from the device file where it’s stored. Write your script so that it opens the file and returns the lines where the data was recorded.
def read_temp_raw(): f = open(device_file, 'r') lines = f.readlines() f.close() return lines
Lastly, you need to manipulate the data so that it’s in the form you want: degrees Celsius. To do that, you just have to strip the data out of the lines, convert it to a float, and divide by 1000.
def read_temp(): lines = read_temp_raw() while lines[0].strip()[-3:] != 'YES': time.sleep(0.1) lines = read_tempt_raw() equals_pos = lines[1].find('t=') if equals_pos != -1: temp_string = lines[1][equals_pos+2:] temp = float(temp_string) / 1000.0 return temp
Finally, your data is in the right form. You’re ready to start publishing it to your AppleTV.
Controlling the Sensor through PubNub
To publish your data, you need to send it to PubNub. But because you only want to send the data when it changes, so as not to clog up your channel to much, you need to write a function that detects changes in the temperature reading. To do this, simply read the data from the sensor twice and store those values in separate variables. Check if the values are the same, and, if they aren’t, publish the new value to the channel.
def sendTemp(): c = int(read_temp()) t = int(read_temp()) if c != t: pubnub.publish(channel=channel, message = {"temp":str(t)}, error=_error)
Now, in order to constantly check if the temperature has changed, you need to continually run the sendTemp() function, which you can do by putting it in a never-ending while loop.
while True: sendTemp()
And, you’re done! You can now remotely monitor the temperature of the water in your kettle through PubNub.
Displaying Numbers on an 8×8 LED Matrix
For this project, your 8×8 LED Matrix serves as a simulation of a thermostat, and it’s your job to program it so that you can change the numbers on it by sending a command through your app, thus increasing the “temperature” of your simulated Smart Home.
Wiring and Initializing the Matrix
To connect the matrix to your Raspberry Pi, you can just directly plug each of the pins on the matrix into the pins on the Pi using five female/female wires. Or, if you want, you can use 10 male/female wires and a breadboard. Like you can see in the diagram below, VCC should go to 5V, GND to Ground, DIN to GPIO 10 (MOSI), CS to GPIO 8 (SPI CS0), and CLK to GPIO 11 (SPI CLK).
To set it up in your script, you just need to write one line of code assigning it to a variable.
device = led.matrix(cascaded=1)
Writing the Number Functions
In order to display numbers on your LED matrix, you first have to hard code those functions in your program. If you want to figure out the pixel arrangements on your own, go for it! If that doesn’t seem like your cup of tea, I’ve done the grunt work for you. Just check out the print functions like the one below in the Github documentation for this project.
def print8(): device.pixel(2, 3, 1, redraw=True) device.pixel(2, 2, 1, redraw=True) device.pixel(2, 1, 1, redraw=True) device.pixel(3, 3, 1, redraw=True) device.pixel(4, 1, 1, redraw=True) device.pixel(4, 2, 1, redraw=True) device.pixel(4, 3, 1, redraw=True) device.pixel(5, 1, 1, redraw=True) device.pixel(6, 3, 1, redraw=True) device.pixel(6, 2, 1, redraw=True) device.pixel(6, 1, 1, redraw=True) device.pixel(5, 3, 1, redraw=True) device.pixel(3, 1, 1, redraw=True)
After you have all your number functions written, you just need to write a simple function that will take two input digits and display them on the matrix when the function is called.
def writeTherm(t,d): t = int(t) d = int(d) if t==5: print50() if t==6: print60() if t==7: print70() if t==8: print80() if d==0: print0() if d==1: print1() if d==2: print2() if d==3: print3() if d==4: print4() if d==5: print5() if d==6: print6() if d==7: print7() if d==8: print8() if d==9: print9()
Communicating with PubNub
Now it’s time to add to the callback function again. This time search the received message for a key called “thermostat.” If it has a value, meaning the app has signaled a desired change in temperature, simply call the function to show that number on the matrix.
def _callback(m, channel): if m.get("thermostat") != None: device.clear() writeTemp(str(m.get("thermostat"))[0],str(m.get("thermostat"))[1])
After finishing this step, you should be able to control the numbers on your matrix from the PubNub Debug Console. Try it out!
Incorporating Presence
The last part of setting up the Raspberry Pi is incorporating PubNub’s presence feature. To make it easier to work with the AppleTV, you'll need to send out the initial states of all the components when a new user joins the channel by opening up the app. To do this, simply use the presence() method and a different callback function to publish the states of each component. For our purposes, only the LED and the temperature sensor have unique states at the start of the program. The thermostat just has a default setting.
def pcallback(m, channel): if m['action'] == 'join': if GPIO.input(LED_PIN)==1: pubnub.publish(channel=channel, message={"light":"on","thermostat":"73", "temp":str(int(read_temp()))}) elif GPIO.input(LED_PIN)==0: pubnub.publish(channel=channel, message={"light":"off","thermostat":"73", "temp":str(int(read_temp()))}) pubnub.presence(channel=channel, callback=pcallback, error=_error)
And, you’re done! Congratulations, you’ve just completed the first part of your simulated smart home.
Next Steps
Now that you've finished with the hardware, it's time to program your AppleTV to control the Raspberry Pi. Keep an eye out for Part 2 of this tutorial so that you can finish building your simulated home of the future, and be one step closer to designing the smart home of your dreams.