I have some functions that drive RGB LEDs with nested for loops but the code examples use time.sleep() and this blocks the rest of my code from running. I want to remove the time sleep from the for loops but do not know how to do it.
I made this timer function but it does not work.
currentTime = int(round(time.time() * 1000))
blinkWait = int(round(time.time() * 1000))
def CheckTime( lastTime, wait):
if currentTime - lastTime >= wait:
lastTime += wait
return True
return False
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
for j in range(256*iterations):
for i in range(strip.numPixels()):
strip.setPixelColor(i, wheel((int(i * 256 / strip.numPixels()) + j) & 255))
if CheckTime(blinkWait,50):
blinkWait = int(round(time.time() * 1000))
strip.show()
I have tried to implement a timer that gets the current time and then checks the time elapsed but could not integrate it into the for loop.
These are the original example LED pattern code functions with the time.sleep() that I want to remove.
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
for j in range(256*iterations):
for i in range(strip.numPixels()):
strip.setPixelColor(i, wheel((int(i * 256 / strip.numPixels()) + j) & 255))
strip.show()
time.sleep(wait_ms/1000.0)
def theaterChaseRainbow(strip, wait_ms=50):
"""Rainbow movie theater light style chaser animation."""
for j in range(256):
for q in range(3):
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, wheel((i+j) % 255))
strip.show()
time.sleep(wait_ms/1000.0)
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, 0)
Thank you in advance.
Update
I tried to wrap the timer around the function call but that doesn't work either. There has to be a way to have a non blocking delay between iterations in a for loop but I am at a loss.
rainbowCycle(strip)
blinkWait = int(round(time.time() * 1000))
Update #2
curr_thread = threading.Thread(target=theaterChaseRainbow, args=(strip))
curr_thread.daemon = False
curr_thread.start()
but I get this error "TypeError: theaterChaseRainbow() argument after * must be an iterable, not Adafruit_NeoPixel"
I also tried putting the strip arg directly in the function. This removes the error but then nothing happens.
def theaterChaseRainbow(strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)):
Update #3
At the suggestion of @Aprillion I revisited the possible duplicate post. I did my best to integrate those suggestions to my code. I added a thread as follows
def theaterChaseRainbow(strip):
"""Rainbow movie theater light style chaser animation."""
for j in range(256):
for q in range(3):
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, wheel((i+j) % 255))
strip.show()
#time.sleep(.05)
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, 0)
def myTimer(seconds):
time.sleep(seconds)
theaterChaseRainbow(strip)
Then in the main loop I call:
myThread = threading.Thread(target=myTimer, args=(.05,))
myThread.start()
This almost works. It displays the and blinks the LEDs but it is much more erratic and not smooth. I think it is because the time.sleep
is in a nested for loop and not for the whole function. How do I make just the second part of the loop sleep? I left the original time.sleep(.05)
as a comment in the function code.