Mood lighting with Raspberry Pi



Mood lighting or ambience lighting refers to using different colors of light to create an ambience reflecting a particular mood. With incandescent or CFL bulbs, mood lighting was very restrictive - color of the light would be restricted to the color of the enclosure of the bulb. However advent of RGB (Red Green Blue) LEDs has opened up a new dimension in mood lighting. A good example is Philips Hue (http://www2.meethue.com/en-xx/). Not only one is not restricted by the color of the enclosure, one gets a choice of colors not previously possible which can be dynamically changed too!!

If you don't want to invest in a proprietary solution, here's one way to achieve the same using RGB LED strip and RPi.

Hardware

A typical RGB strip needs 12V. However, RPi provides only 3.3V at the GPIO pins. Hence we need a bridge between these two circuits. A ULN2803 chip acts as this bridge - it takes TTL input and allows one to drive a high voltage circuit.



Software

We will use raspberry-gpio-python to control the GPIO from python (v2.7). We will write a simple webserver which will take color hexcode as a query string and apply Pulse Width Modulation (PWM) to generate the same at RPi output.

Install raspberry-gpio-python package

Download tar from http://sourceforge.net/p/raspberry-gpio-python
gunzip RPi.GPIO-0.5.11.tar.gz
tar xvf RPi.GPIO-0.5.11.tar
cd RPi.GPIO-0.5.11
sudo python setup.py install
In a different directory, create two files pwm.py and server.py as listed below. 

pwm.py

#!/usr/bin/python
#Controlling a RGB LED with software PWM.
#Mostly copied from GPIO PWM example:
#http://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/

import time
import RPi.GPIO as GPIO
import math

GPIO.setmode (GPIO.BOARD)
red = 12
#pin numbers to match LED legs
green = 16
blue = 18

GPIO.setup (red, GPIO.OUT)
#setup all the pins
GPIO.setup (green, GPIO.OUT)
GPIO.setup (blue, GPIO.OUT)

Freq = 100
#Hz
#setup all the colours
RED = GPIO.PWM (red, Freq)
#Pin, frequency
RED.start (0)
#Initial duty cycle of 0, so off
GREEN = GPIO.PWM (green, Freq)
GREEN.start (0)
BLUE = GPIO.PWM (blue, Freq)
BLUE.start (0)

def colour (R, G, B):
#colour brightness range is 0-100
  RED.ChangeDutyCycle (R)
  GREEN.ChangeDutyCycle (G)
  BLUE.ChangeDutyCycle (B)

def hex_to_argb(value):
    lv = len(value)
    return tuple((int(value[i:i + lv // 4], 16) * 100)/255 for i in range(0, lv, lv // 4))

'''
try:
    while 1:
        colour(0, 0, 100)
except KeyboardInterrupt:
    pass
'''

def stop():
    #Stop all the PWM objects
    RED.stop ()
    GREEN.stop ()
    BLUE.stop ()

    #Tidy up and remaining connections.
    GPIO.cleanup ()


server.py

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from urlparse import urlparse, parse_qsl
import cgi
from pwm import hex_to_argb, colour, stop

class GetHandler (BaseHTTPRequestHandler):
    def do_GET (self):
        parsed_path = urlparse (self.path)
        message_parts =['CLIENT VALUES:',
                  'client_address=%s (%s)' % (self.client_address,
                                              self.address_string ()),
                  'command=%s' % self.command,
                  'path=%s' % self.path,
                  'real path=%s' % parsed_path.path,
                  'query=%s' % parsed_path.query,
                  'request_version=%s' % self.request_version,
                  '',
                  'SERVER VALUES:',
                  'server_version=%s' % self.server_version,
                  'sys_version=%s' % self.sys_version,
                  'protocol_version=%s' % self.protocol_version,
                  '', 'HEADERS RECEIVED:',]
        q = parse_qsl(parsed_path.query)

        for k,v in q:
            if (k == "color"):
                self.execute(v)

        for name, value in sorted (self.headers.items ()):
            message_parts.append ('%s=%s' %
                            (name,
                             value.rstrip ()))
            message_parts.append ('')
        message = '\r\n'.join (message_parts)
        self.send_response (200)
        self.end_headers ()
        self.wfile.write (message.encode ())
        return

    def execute(self, color):
        print("color = " + color)
        c = hex_to_argb(color)
        print(c)
        colour(*c[1:])

    def do_POST(self):
    # Parse the form data posted
        form = cgi.FieldStorage(
            fp=self.rfile,
            headers=self.headers,
            environ={'REQUEST_METHOD':'POST',
                 'CONTENT_TYPE':self.headers['Content-Type'],
                  })
        for field in form.keys():
           print field
           if (field == "color"):
               v = form[field].value
               self.execute(v)
        # Begin the response
        self.send_response(200)
        self.end_headers()

if __name__  == '__main__':
    PORT = 8080
    server = HTTPServer (("", PORT), GetHandler)
    print ('Starting server, use <Ctrl-C> to stop')
    server.serve_forever ()


Since we will be handling low level IO functions, we need to run this server as root.

sudo python server.py

Now we can use curl to change the color as we want by passing color hexcode in argb format (1 byte each for alpha, red, green and blue). e.g. to get red color, use

curl http://<rpi-ip-addr>:8080 -d color=ffff0000

Or use a browser:

http://<rpi-ip-addr>:8080/?color=ffff0000


Comments

Popular posts from this blog

GNU Emacs as a Comic Book Reader

Data Visualization with GNU Emacs

Mozilla Readability in GNU Emacs