2

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.

lukecv
  • 113
  • 1
  • 11
  • 1
    Possible duplicate of [Non-polling/Non-blocking Timer?](https://stackoverflow.com/questions/22180915/non-polling-non-blocking-timer) – Aprillion May 25 '19 at 12:47
  • 1
    This calls for a multi-threaded solution. If your `strip` object is thread-safe, you could try calling either `rainbowCycle` or `theaterChaseRainbow` in separate threads. See [here](https://stackoverflow.com/a/2906014/3388962) for an example how this is done. – normanius May 25 '19 at 12:56
  • @Aprillion thank you, I read that post earlier and have been trying to impliment it in the for loop without success. I have also been trying to create a thread. that is called. I added my attempt at a thread to the original post. – lukecv May 25 '19 at 13:10
  • I tried to use the suggestions from the possible duplicate [Non-polling/Non-blocking Timer](https://stackoverflow.com/questions/22180915/non-polling-non-blocking-timer) example but I do not think that is an exact duplicate of my question since the `time.sleep()` is in a function with a nested for loop. Thank you for your suggestions so far. I also tried on the simpler function `rainbowCycle(strip)` since it only has two loops. It also flashes and stutters in strange ways. I think it is because the delay needs to be in the loop but calling the function every .05 seconds is not the same. – lukecv May 25 '19 at 13:30
  • 1
    you can also check https://docs.python.org/3/library/asyncio-task.html without threads,, but I have no idea what is the `strip` object and how to call the 2 functions to provide a full answer – Aprillion May 25 '19 at 13:40

0 Answers0