Sunrise LED Strip Simulation Using Raspberry Pi

What to buy

  1. Raspberry Pi
  2. Adafruit digital RGB LED strip
  3. 5V power block
  4. power adapter
  5. breadboard and GPIO cobbler

When you are looking for LED strips, you will find two types of LED strips: digital RGB LED strip and typical RGB LED strip. The difference between these two types of LED strips is that digital RGB need two input into the strip for the light control whereas typical RGB strip needs three PWM controlled inputs into the strip. Adafruit’s digital RGB LED strip (https://www.adafruit.com/products/306) provides PWM control embedded in each LED chipset and you do not have to worry about PWM output control from your Raspberry Pi.

When powering the LED strip, you need a separate power sources for Raspberry Pi and your LED strip. LED strip must be powered by a separate 5V power block (https://www.adafruit.com/products/276). Since Raspberry Pi and LED strip has to be gounded together, power adapter (https://www.adafruit.com/products/368) which separates power and ground cable allows you to connect the ground with ease.

The circuit diagram is as follows.

RPi_LEDStrip_bb.png

Raspberry Pi and LED strip connections

To control the LED strip through Raspberry Pi, you need to connect to SPI pins on GPIO. MOSI from Raspberry Pi gets connected to DI on the LED strip. SCLK from Raspberry Pi gets connected to CI on the LED strip. Make sure you are not connecting to DO/CO on the LED strip which is the output end.

More detailed explanation is provided here (https://github.com/ManiacalLabs/BiblioPixel/wiki/SPI-Setup).

Python Dependency

BiblioPixel library provides simple implementation of LED strip control. For SPI control from Raspberry Pi, you need to first enable hardware SPI control by entering rasp-config from command line. All pip dependencies are as followed.

BiblioPixel==2.0.5
Django==1.8.5
MySQL-python==1.2.5
pyserial==2.7
RPi.GPIO==0.5.11
spidev==3.1
wheel==0.24.0

Code Implementation

There were two parts to the code implementation.

  1. turning LED lights on gradually from red to bright white color.
  2. listening to button press to turn off the light

My initial attempt was using threading module to create two threads which do aformentioned tasks. Threading was implemented but I had to change my implementation due to two reasons.

  1. Threading to turn on LED lights does not give you precise timing control since threading event depends on the scheduler for execution.
  2. Button listener throwing an exception at a button click event could not be caught from the main process. Child thread gets its own stack and exception handling between the main thread and the child thread was not simple enough.

Therefore, I had to just simulate threading procedure where I continuously poll for button press after each LED light update. This seemed to be working but putting time.sleep() made button listener to not function as well when python is in sleep. I then broke down time.sleep() into small frames of time.sleep() + button polling to allow button listening to function even at waiting stage.

My final attempt will involve LED lighting implemented with multiprocessing.Process() and constant polling for the button press in a while loop in the main process. This way multiprocessing will allow constant rate of change in LED lighting, be able to kill the process at a button press, and turn off all the lights at the end.

from __future__ import division
import time
import sys
import multiprocessing

import RPi.GPIO as GPIO

from bibliopixel.led import *
from bibliopixel.drivers.LPD8806 import *


WAIT_INTERVAL = 0.1
NUMBER_OF_LED = 96

class SunriseSimulator(multiprocessing.Process):
	"""This class is to interact with LPD8806 digital RGB strip simulating sunrise effect"""
	
	def __init__(self, name):
		multiprocessing.Process.__init__(self)
		self.name = name
		self.driver = DriverLPD8806(NUMBER_OF_LED,c_order=ChannelOrder.GRB)
		self.led = LEDStrip(self.driver)

	def run(self):
		"""turns on all led bulbs gradually from dim red to bright white light"""
		driver = self.driver
		led = self.led
		
		#RGB pixel status
		r=0
		g=0
		b=0
		
		#Gradual red light increase
		for red in range(256):
			r = red
			led.fillRGB(r,g,b)
			led.update()
			print (r,g,b)
			time.sleep(WAIT_INTERVAL)
		
		#green and blue light intensity increase	
		for n in range(256):
			g = n
			led.fillRGB(r,g,b)
			led.update()
			print (r,g,b)
			time.sleep(WAIT_INTERVAL)
		
			b = n
			led.fillRGB(r,g,b)
			led.update()
			print (r,g,b)
			time.sleep(WAIT_INTERVAL)

		while True:
			pass


	def turn_off_led(self):
		"""turns off all the led lights"""
		self.led.all_off()
		self.led.update()

       
class ButtonListener():
	def __init__(self):
		return
		
	def activate_button(self):
		GPIO.setmode(GPIO.BCM)
		GPIO.setup(18,GPIO.IN, pull_up_down=GPIO.PUD_UP)
	
	def button_is_clicked(self):
		input_state = GPIO.input(18)
		if input_state == False:
			print 'Button is clicked'
			return True
		return False

		
if __name__ == "__main__":
	try:
		#initialize led controller and button listener
		sunrise_instance = SunriseSimulator("LED_Controller")
		button_listener = ButtonListener()
		button_listener.activate_button()
		
		#start turning on led with seperate process
		sunrise_instance.start()
		
		#listen for button click event
		while not button_listener.button_is_clicked():
			pass
	
		#terminate the process run and turn off all the light
		sunrise_instance.terminate()
		sunrise_instance.turn_off_led()

	except KeyboardInterrupt:
		pass
The following video shows the LED strip triggered by a HTTP request through Django web framework and turned off with a button press.

Scheduled Task

When a registered user submits their alarm schedule through html form, form data is rendered to Django model which is then associated with the user model. After linking the schedule to the user, python-crontab module is used to modify Linux crontab. For the current implementation, it will remove all the previous cron job and write in a newly scheduled job which will execute the LED control python code.

def update_crontab(minute, hour, day, command):
    day_map = { "1" : "MON",
                "2" : "TUE",
                "3" : "WED",
                "4" : "THU",
                "5" : "FRI",
                "6" : "SAT",
                "7" : "SUN"}
    users_cron = CronTab(user='pi')
    users_cron.remove_all()
    job = users_cron.new(command=command, comment='LED lighting schedule')
    job.hour.on(hour)
    job.minute.on(minute)
    job.dow.on(day_map[day])
    users_cron.write()