Introduction: IoT: DIY Hue Light

About: I'm just happy to be here.

Make a RGB Hue light that you can stream RGB values to from any platform.

IoT devices are expensive, the smart home is not going to be cheap. That's why we become developers and save loads of money by building instead of buying those quirky devices everyone needs.

I am going to walk you through creating your own Hue light with an Android interface. Before we proceed, I recommend you take a look at the other Raspberry Pi tutorials that PubNub offers. This blog post assumes that you have your Raspberry Pi setup and have the PubNub Python SDK installed. If you do not, check out RaspberryPi 101 to catch up. If you have your Pi OS up and running, use this tutorial which just gets the PubNub Python SDK installed on your device.

This demo will use a Python script to control the lights. For a full tutorial on creating an Android client side to control your light, view the PubNub blog posting.

Things you will need

  • Raspberry Pi
  • Breadboard
  • RGB LED
  • 3 ~330 Ohm resistors
  • 4 Male/Female Wires

View the video demo of what you will be making here!

Step 1: Intro to RGB

Not all RGB LEDs are created equal. They can have a shared cathode, or shared anode.

In the common cathode LED, if only the R pin goes high, the light will show red. However, in the common anode LED, if only the R pin goes high, the light will show Cyan. For those of you who skipped that day of middle school art class, green and blue light together make cyan.

This tutorial will be written for an RGB LED using a common anode. I will point out the blocks of code that will need to be different when using a common cathode. Read about your LED before proceeding.

Step 2: GPIO Pin Selection

I built my PHue using the RaspberryPi Model B+. You will have to find which pins you want to use, as well as which pin is the 5V power source. If you are using the Model B+ or Model B, you can mimic the picture.

You will need to select 3 GPIO pins. Write down the numbers of the pins you select, we will need them in the next step. In this photo, and for the rest of the demo, I will use colored wires that correspond to the same RGB values on the LED (red wire goes to the pin on the LED corresponding with red). The white wire, in this tutorial, is connected to the 5V power supply. If you are using a common cathode the white wire should go to Ground. Connect the female ends of your Male/Female wires to the pins you selected.

Step 3: Breadboard Setup

Now you have your GPIO pins and 5V power source selected and connected. Time to set up the breadboard.

Refer to the RGB LED diagram above again. Notice that the longest wire gets the 5V. You can tell which pin is red since it is on the side of that long pin that only has one pin, not two. From there you can figure out green and blue, they are on the other side of the long pin. In the photo above, the long pin is in the second row from the top, with the white wire. Time for the resistors. I said you will need ~300 Ohms, but notice that I use two different resistors. You can play around with what combination works best for you, but as a rule of thumb, the red light tends to overpower the green and blue, so I put a stronger resistor to reduce the current it receives. When we get our light on in the next step, I will show you how to set it to white. If you notice that the "white" looks a little red, you can change the resistor then.

Regardless of a common anode or cathode RGB, you can set up the breadboard exactly as it appears in this photo. The only difference would be what the female end of the white wire is connected to (again, 5V in common anode, Ground in common cathode).

Step 4: Raspberry Pi Code

PubNub offers a C/C++ library and a Python library to use on Raspberry Pi. I implemented this tutorial in Python. If you missed my earlier advice and still need to install the PubNub Python SDK on your Pi, use this tutorial. If you're ready, then let's get started!

Step 5: Imports and Pin Setup

#!/usr/bin/python
import time
import RPi.GPIO as GPIO
from pubnub import Pubnub

These are all the imports you will need. RPi.GPIO allows you to map the pins on your Pi. We will use time and Pubnub. Time to coordinate color changes in our LED, and Pubnub to stream color values to your PHue light.

Remember those pin assignments you wrote down earlier, now we need them.

## Make your pin assignments
red_gpio   = 18
green_gpio = 23
blue_gpio  = 24

Then we will instantiate our pins using the function `GPIO.setup`. We need to declare the General Purpose Input/Output pins as either an input or an output.

## Setup GPIO Board and Pins
GPIO.setmode(GPIO.BCM) # BCM for GPIO numbering  
GPIO.setup(red_gpio,   GPIO.OUT)
GPIO.setup(green_gpio, GPIO.OUT)
GPIO.setup(blue_gpio,  GPIO.OUT)

The `GPIO.setmode` function tells python what pin numbering system is being used. See this thread for a brief description of the options. The GPIO diagram I used to select pin numberings used the BCM channel design. If you later have issues with this portion, try using the GPIO.BOARD option. `GPIO.setup` is where we declare the pins as input or output. The other option is of course `GPIO.IN` which is used when something like a sensor is returning data to the Pi.

## Init the GPIO PWMs
Freq = 100 #Hz
RED = GPIO.PWM(red_gpio, Freq)
RED.start(0)
GREEN = GPIO.PWM(green_gpio, Freq)
GREEN.start(0)
BLUE = GPIO.PWM(blue_gpio, Freq)
BLUE.start(0)

This code is used for setting up your pins using Pulse Width Modulation. PWM is a method for generating an analog signal using a digital source. It encodes a message into a pulsing signal. The "message" in this case, is the RGB values that each of our pins will be sending to the LED. If you are interested you can read more about PWMs here.

Step 6: The Lighting Code

These pulsing values (on-time and off-time) are called a PWMs Duty Cycle, so the Python function we will be using to set RGB values is `.ChangeDutyCycle()`.

# Update the hue with R G B values
def updateHue(R, G, B):
	rVal = 100 - (R/255.0)*100  # Will have to change these values depending on
	gVal = 100 - (G/255.0)*100  #  on whether your LED has a common cathode or
	bVal = 100 - (B/255.0)*100  #  common anode. This code is for common anode.
	print "rgb(%.2f, %.2f, %.2f)" % (rVal, gVal, bVal)
	RED.ChangeDutyCycle(rVal)
	GREEN.ChangeDutyCycle(gVal)
	BLUE.ChangeDutyCycle(bVal)

Since our PWM is pulsing at 100Hz, we must give it a value between 0.0 and 100.0 for its Duty Cycle. 100.0 means the pin always stays high, 0.0 means it always stays low. As anyone who has worked with CSS knows, color values are often represented by 6-digit Hex values. To fit RGB values into 6 digits of hex, each color actually has `2^8 = 256` possible choices (0-255). That said, we now need to find the proportional value of our desired RGB out of 100. For example, a given R value out of 100 is `(R/255.0)*100`.

This part is especially different for common anode and common cathode LEDs!

If you are using a common cathode (meaning the long pin is connected to Ground), you should use the code `rVal = (R/255.0)*100`. However, if you are using a common anode (5V to long pin), like me, you will need to use `rVal = 100 - (R/255.0)*100`

rVal = (R/255.0)*100			# Common Cathode (Ground)
rVal = 100 - (R/255.0)*100		# Common Anode (5V)

Think of it this way, Ground is low, 5V is high. If the long pin is going to Ground, you will need the RGB values to go high and give the LED power. If I want the light red, I want to send a `rVal` of 100.0. If the long pin is connected to the 5V, I am effectively resisting the 5V current by sending currents from the GPIO pins. If I want the common anode light to show red, I want `rVal` of 0.0 (no resistance on the red current) and a `gVal` and `bVal` of 100.0 to resist both of those color currents.

Step 7: Quick Test and Debug

You have everything connected now, so let's run a quick test to make sure that everything is working.

def rgb():
	updateHue(255,0,0); time.sleep(2)
	updateHue(0,255,0); time.sleep(2)
	updateHue(0,0,255); time.sleep(2)

This function will set the light to RED -> GREEN -> BLUE for 2 seconds each. Let's make a quick `main` function and run it.

def main():
	rgb()
	updateHue(0,0,0); # Light off
	
main()

Save this file as `PHue.py` Then open the terminal on your pi and `cd` into the working directory. Then run your python program.

	$ cd <project directory>
	$ sudo python PHue.py 

You should see your light flash in the order RED -> GREEN -> BLUE. You may have to change the board layout or if you realize they flash in a different order you may have it wired slightly incorrectly. Make sure it goes Red then Green then Blue though, we cannot properly mix colors unless all pins are working correctly.

Do not continue unless it does exactly this.

If you made it this far take a deep breath, the hard part is over and you have successfully wired and programmed a RGB LED, pretty cool!

Step 8: Streaming Data

In order to start streaming data to your PHue light, you will need a publish and subscribe key. To get your pub/sub keys, you’ll first need to [sign up for a PubNub account](http://www.pubnub.com/get-started/). Once you sign up, you can find your unique PubNub keys in the [PubNub Developer Dashboard](https://admin.pubnub.com). The free Sandbox tier should give you all the bandwidth you need to build and test PHue lightbulb.

Once you have those, you will need to subscribe to a channel. Adding the following lines of code to your `main` function will accomplish this.

def main():
	# Instantiate Pubnub...
	pubnub = Pubnub(publish_key = 'your-pub-key',
					subscribe_key = 'your-sub-key')

	# This is the channel your Pi will be listening on for RGB values
	channel = 'phue' 

	# The callback tells pubnub what to do when it received a message.
	def _callback(msg, n):
		print(msg)
		updateHue(msg["RED"], msg["GREEN"], msg["BLUE"])

	def _error(m):
		print(m)

	pubnub.subscribe(channels=channel, callback=_callback, error=_error)

First, we create an instance of Pubnub, all this requires is your publish and subscribe keys from your dashboard. Then we decide what channel we want out Pi to subscribe to. In order to subscribe you need a channel to listen in on, a callback that will be called when a message is received, and an error callback that will be triggered if any problems are encountered.

Take a look at out callback. The message we receive will be in JSON format, and it will have three fields, RED, GREEN, and BLUE. For example the message we receive for white light may look like this:

{'RED':255, 'GREEN':255, 'BLUE':255}

So long as the JSON object we stream to the Pi has those three fields, we can now send hues from any of PubNubs 70+ SDKs, controlling it from anywhere.

Step 9: An Example in Python

As I said, you only need to stream data in JSON format that contains a RED, GREEN, and BLUE key.

Here is a simple example in python that will change your light to whatever RGB values you publish from the python script. Save this in your project directory as hueStream.py.

from Pubnub import Pubnub
import sys
def main():
	if len(sys.argv) < 4:
		print "Improper Usage"
		print "python test.py <RED> <GREEN> <BLUE>"
		sys.exit(0)
	R=int(sys.argv[1])
	G=int(sys.argv[2])
	B=int(sys.argv[3])
	data = {
		'RED' : R,
		'GREEN':G,
		'BLUE': B
	}
	pubnub = Pubnub(publish_key = 'your-pub-key',
			subscribe_key = 'your-sub-key')
	channel = 'phue'
	pubnub.publish(channel, data)
main()

To use this script, open your terminal and go to your project directory then supply it with three red green and blue values, as follows.

$ cd <project-dir>
$ sudo python hueStream.py 255 255 255

This will stream white to your light.

You can stream JSON from Pubnub in any of the 70+ languages they provide SDKs for, or using their REST API for unsupported languages.

I implemented an example of streaming data in android. You can clone my GitHub repository and modify the publish and subscribe keys found in MainActivity.java to make it work with your light!

That's all I have for you. Until next time, good work!