I'm trying to use python to turn on some RGB lights after motion is detected. My code is below but I can't get the thread to end and switch off the LEDS. All that happening is I get stuck after keyboard interrupt.
Essentially when I run the code it works to detect movement and switch the lights on but then when I try to end the program with a keyboard interupt exception either the program hangs and doesn't stop or it stops but the LEDs don't switch off and stay lit. I've looked at various pages about how to stop a thread running but none of it has helped. Below are the articles I've looked at. I think my issue is that the thread running the lighting pattern loop isn't stopping so when I try to turn each LED off its turned back on immediately but I'm not sure.
I can't get the thread to stop any way I've tried. Any help would be much appreciated.
https://www.oreilly.com/library/view/python-cookbook/0596001673/ch06s03.html
https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 1 10:10:25 2020
@author: thomas
"""
import RPi.GPIO as GPIO
import time
import subprocess
import argparse
from neopixel import *
import datetime as dt
from threading import Thread
from threading import enumerate
from threading import Event as EV
import sys
global stop
GPIO.setmode(GPIO.BCM)
# LED strip configuration:
LED_COUNT = 288 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0
LED_STRIP = ws.SK6812_STRIP_RGBW
#LED_STRIP = ws.SK6812W_STRIP
# Define functions which animate LEDs in various ways.
def wheel(pos):
"""Generate rainbow colors across 0-255 positions."""
if pos < 85:
return Color(pos * 3, 255 - pos * 3, 0)
elif pos < 170:
pos -= 85
return Color(255 - pos * 3, 0, pos * 3)
else:
pos -= 170
return Color(0, pos * 3, 255 - pos * 3)
def colorWipe(strip, color, wait_ms=20):
"""Wipe color across display a pixel at a time."""
for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
time.sleep(wait_ms/1000.0)
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
while not stop:
for j in range(256*iterations):
for i in range(strip.numPixels()):
strip.setPixelColor(i, wheel(((i * 256 // strip.numPixels()) + j) & 255))
strip.show()
time.sleep(wait_ms/1000.0)
class RainbowLights(Thread):
def __init__(self, name="RainbowLights"):
self._stopevent = EV()
self.sleeppreiod = 1.0
Thread.__init__(self, name=name)
def run(self):
while not self._stopevent.isSet():
rainbowCycle(strip)
self._stopevent.wait(self._sleepperiod)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
args = parser.parse_args()
# Create NeoPixel object with appropriate configuration.
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
# Intialize the library (must be called once before other functions).
strip.begin()
print ('Press Ctrl-C to quit.')
if not args.clear:
print('Use "-c" argument to clear LEDs on exit')
GPIO.setup(22, GPIO.IN) #PIR
rta = "none"
time1 = "none"
stop = False
RainbowLights = RainbowLights()
try:
time.sleep(2) # to stabilize sensor
while True:
trigger = GPIO.input(22)
if trigger == 1:
print("Motion Detected...")
if rta == "running":
print("Lights Already On")
else:
RainbowLights.start()
rta = "running"
time1 = dt.datetime.now()
time.sleep(5) #to avoid multiple detection
elif trigger == 0:
print("No Motion...")
print("Lights turned on at " + str(time1))
time.sleep(0.1) #loop delay, should be less than detection delay
except KeyboardInterrupt:
RainbowLights._stopevent.set()
stop = True
time.sleep(5)
if args.clear:
colorWipe(strip, Color(0,0,0), 10)
GPIO.cleanup()