jamesrussell
Posts: 7
Joined: Sat Dec 21, 2013 3:34 pm

Python Christmas Lights

Sat Dec 21, 2013 3:43 pm

Hi All,

I am looking for some help with my Christmas lights project. I have decided to start playing with Python and GPIO and thought as it's christmas it would be an interesting learning experience.

So far I have got a working circuit and can flash two sets of LED christmas lights using sequences I have set in Python. I have a button on the board too, this is also confirmed working I can use it to start a sequence.

What I am looking to accomplish is having a sequence start when the program starts and use the button to change the sequence.

I am sure I need to use threading and interrupts but I am not getting the results I was hoping for. The button running in it's own thread works fine and I can get it to print to screen on input but when controlling the lights thread it waits until the thread is complete to receive another input.

I assume what I need is:
Interrupt (from button)
Stop lights thread
Pick next in sequence
Start Lights Thread

Any help would be great, I have been going over it all night and am lost!

Thanks

Code: Select all

import RPi.GPIO as GPIO
import time
import threading
from threading import Thread

GPIO.setmode(GPIO.BOARD)
GPIO.setup(26, GPIO.OUT)
GPIO.setup(18, GPIO.OUT)
GPIO.setup(16,GPIO.IN)
red = 26
blue = 18

def reset():
        GPIO.output(26, True)
        GPIO.output(26, False)
        GPIO.output(18, True)
        GPIO.output(18, False)

def blink(repeat, colour, speed):
        for n in range(repeat):
                GPIO.output(colour, True)
                time.sleep(speed)
                GPIO.output(colour, False)
                time.sleep(speed)
                

def end():
    GPIO.cleanup()
    raise SystemExit
    return

def setone():
        reset()
        blink(2, red, .5)
        blink(4, blue, .5)
        blink(6, red, .025)
        blink(6, blue, .05)
        blink(7, red, .1)
        return

def settwo():
        reset()
        blink(6, red, .025)
        blink(6, blue, .025)
        blink(3, red, .1)
        blink(3, blue, .1)
        for n in range(64):
                blink(1, red, .025)
                blink(1, blue, .025)
        return

def setthree():
        reset()
        blink(4, blue, .5)
        blink(4, red, .5)
        blink(2, blue, .025)
        blink(2, red, .025)
        for n in range(128):
                blink(1, blue, .02)
                blink(1, red, .02)
        return

def button():
        GPIO.add_event_detect(16, GPIO.RISING, callback=alert, bouncetime=150)
def lights(func):
                reset()
                func()
                
def alert(channel):
        seq = [setone, settwo, setthree]
        reset()
        print "Detected"
        print str(seq[0])
        sq = seq[0]
        Thread(target = lights(seq[0])).join()

if __name__ == '__main__':
        Thread(target = button).start()
        Thread(target = lights(setone)).join()

User avatar
davef21370
Posts: 897
Joined: Fri Sep 21, 2012 4:13 pm
Location: Earth But Not Grounded

Re: Python Christmas Lights

Sat Dec 21, 2013 5:10 pm

Why have the button in a thread, just put it in an infinite loop and have it control the light thread.

Dave.
Apple say... Monkey do !!

jamesrussell
Posts: 7
Joined: Sat Dec 21, 2013 3:34 pm

Re: Python Christmas Lights

Sat Dec 21, 2013 5:19 pm

davef21370 wrote:Why have the button in a thread, just put it in an infinite loop and have it control the light thread.

Dave.
That sounds good to me, I guess the button can just be in main. I am just not sure how to control the lights thread to change the sequence, any ideas?

User avatar
Douglas6
Posts: 4874
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Python Christmas Lights

Sat Dec 21, 2013 5:44 pm

My Python is sketchy at best, but two things, I think.
One, the button rising edge interrupt is already running in it's own thread provided by RPi.GPIO (or is using real interrupts, same effect)
Two, you could just as well run the light sequence in the main thread. It will be interrupted when the button is pressed.

I would re-think this to not use Thread at all, but put a loop in the main thread to run a sequence, and use the button call back to change which sequence it's running.

jamesrussell
Posts: 7
Joined: Sat Dec 21, 2013 3:34 pm

Re: Python Christmas Lights

Sat Dec 21, 2013 5:57 pm

Douglas6 wrote:My Python is sketchy at best, but two things, I think.
One, the button rising edge interrupt is already running in it's own thread provided by RPi.GPIO (or is using real interrupts, same effect)
Two, you could just as well run the light sequence in the main thread. It will be interrupted when the button is pressed.

I would re-think this to not use Thread at all, but put a loop in the main thread to run a sequence, and use the button call back to change which sequence it's running.
Interesting, thanks. I will see what I can do. I did try to have the interrupt end a loop but I could not seem to get that to work. How would I break the loop using the interrupt. I think I had something like:

Code: Select all

def lights(fund):
     try:
         while True:
         #Things to loop here
except #condition
I could not find the right condition to make it break the loop on the interrupt. Maybe because they were in separate threads? Sorry I am very much a beginner with Python and total GPIO newbie. My job is a PHP and Database guy.

Thanks

User avatar
Douglas6
Posts: 4874
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Python Christmas Lights

Sat Dec 21, 2013 6:23 pm

Simplest would be to just let a sequence run out before changing to the next sequence:

Code: Select all

while True:
    if (sequence == 1):
        setone()
    if (sequence == 2):
        settwo()
    if (sequence == 3):
        setthree()
If you really need it to stop mid-sequence, it quickly gets messier

jamesrussell
Posts: 7
Joined: Sat Dec 21, 2013 3:34 pm

Re: Python Christmas Lights

Sat Dec 21, 2013 6:45 pm

Douglas6 wrote:Simplest would be to just let a sequence run out before changing to the next sequence:

Code: Select all

while True:
    if (sequence == 1):
        setone()
    if (sequence == 2):
        settwo()
    if (sequence == 3):
        setthree()
If you really need it to stop mid-sequence, it quickly gets messier

Mid sequence stopping is a nice to have, certainly not essential!

That looks great, now I just need to find a way to alter the sequence variable based on the button input. I'll give it a go.

Thanks a bunch.

User avatar
Douglas6
Posts: 4874
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Python Christmas Lights

Sat Dec 21, 2013 6:55 pm

You didn't hear it from me, but I'd simply make sequence a global variable. And then read up on why global variables are evil, while you enjoy your festive holiday light display.
Last edited by Douglas6 on Sat Dec 21, 2013 7:10 pm, edited 1 time in total.

jamesrussell
Posts: 7
Joined: Sat Dec 21, 2013 3:34 pm

Re: Python Christmas Lights

Sat Dec 21, 2013 6:58 pm

Douglas6 wrote:You didn't hear it from me, but I'd simply make sequence a global variable. And then read up on why global variables are evil.
Lol, i'd already started along that line!

jamesrussell
Posts: 7
Joined: Sat Dec 21, 2013 3:34 pm

Re: Python Christmas Lights

Sat Dec 21, 2013 7:14 pm

jamesrussell wrote:
Douglas6 wrote:Simplest would be to just let a sequence run out before changing to the next sequence:

Code: Select all

while True:
    if (sequence == 1):
        setone()
    if (sequence == 2):
        settwo()
    if (sequence == 3):
        setthree()
If you really need it to stop mid-sequence, it quickly gets messier

Mid sequence stopping is a nice to have, certainly not essential!

That looks great, now I just need to find a way to alter the sequence variable based on the button input. I'll give it a go.

Thanks a bunch.

Okay, feeling really stupid now but I can't get this to work. Sure it is simple but I cannot get even get the 'Detected' to print when the sequence is running.

If you could shine a light I would be very happy.

Code: Select all

sequence = 1

GPIO.add_event_detect(16, GPIO.RISING, bouncetime=500)

if (GPIO.event_detected(16)):
        print('Pressed')
        sequence = 2


while True:
        
        if (sequence == 1):
                setone()
        if (sequence == 2):
                settwo()
        if (sequence == 3):
I just want it to change to sequence 2 on input. Pretty sure I could figure it out from there.

User avatar
Douglas6
Posts: 4874
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Python Christmas Lights

Sat Dec 21, 2013 7:31 pm

Untested, but this is what I had in mind:

Code: Select all

def alert():
    global sequence
    sequence += 1
    if (sequence > 3):
        sequence = 1

GPIO.add_event_detect(16, GPIO.RISING, callback=alert, bouncetime=150)

jamesrussell
Posts: 7
Joined: Sat Dec 21, 2013 3:34 pm

Re: Python Christmas Lights

Sat Dec 21, 2013 10:02 pm

Douglas6 wrote:Untested, but this is what I had in mind:

Code: Select all

def alert():
    global sequence
    sequence += 1
    if (sequence > 3):
        sequence = 1

GPIO.add_event_detect(16, GPIO.RISING, callback=alert, bouncetime=150)
Thank You!!!!! So much. Works perfectly!

Lots of stupid lights flashing now.

Happy Christmas/Holidays/Festivus to you

Jimi

Return to “Python”