Isaac Decker
Isaac Decker

Reputation: 66

python ws281x show function having different timings in different functions

I wrote a python script using the rpi_ws281x library that can animate an led strip attached to my rpi. The time it takes to run strip.show() in color_fade takes longer than when updating it directly in the run_animation function. The delay is consistent too. I'm curious what's happening and if it can be fixed.

import threading
import time
from guy import Guy,http
import json
import sys
import requests
from rpi_ws281x import Color, PixelStrip, ws
from rgbw_colorspace_converter.colors.converters import RGB, Hex
    
def set_sec(color, first, last):
    last += 1
    for i in range((last-first)):
        strip.setPixelColor(first + i, color)
    strip.show()

def color_fade(color_from, color_to, time_len, start_led, end_led):
    step_len = 5
    steps = int(time_len/step_len)

    step_R = (int(color_to[0]) - int(color_from[0])) / steps
    step_G = (int(color_to[1]) - int(color_from[1])) / steps
    step_B = (int(color_to[2]) - int(color_from[2])) / steps
    step_W = (int(color_to[3]) - int(color_from[3])) / steps
    r = int(color_from[0])
    g = int(color_from[1])
    b = int(color_from[2])
    w = int(color_from[3])
    print("start")
    for _ in range(steps):
        # This runs consistently slower, even with no delays/sleeps
        start_time = time.time()
        c = Color(int(r), int(g), int(b), int(w))
        set_sec(c, start_led, end_led)
        end_time = time.time()
        print(f"Update time: {end_time - start_time} seconds") #0.03s
        #time.sleep(step_len / 1000)
        # Fading code, intentionally disabled
        #print(r)
        #print(step_R)
        #r += step_R
        #g += step_G
        #b += step_B
        #w += step_W
    print("end")

killpills = {}

def run_animation(anim, loop, index):
    if (loop):
        print(killpills)
        while killpills["anim" + str(index)]:
            for i in range(len(anim)):
                color = Hex(anim[i]["color"]).rgbw
                if (anim[i]["tran"] == 'jump'):
                    if (anim[i]["type"] == 'bulb'):
                        requests.post('http://' + anim[i]["ip"] + '/cm?cmnd=color%20' +
                                      str(color[0]) + ',' + str(color[1]) + ',' + str(color[2]) + ',' + str(color[3]))
                    elif (anim[i]["type"] == 'strip'):
                        # This runs quickly, even when looping it a bunch
                        start_time = time.time()
                        color = Color(color[0],color[1],color[2],color[3])
                        set_sec(color, int(anim[i]["start"]), int(anim[i]["end"]))
                        end_time = time.time()
                        print(f"Update time: {end_time - start_time} seconds") #0.01s
                    time.sleep(int(anim[i]["time"])/1000)
                elif (anim[i]["tran"] == 'fade'):
                    if (not i == len(anim)-1):
                        color_fade(color, Hex(anim[i+1]["color"]).rgbw, int(anim[i]["time"]), int(anim[i]["start"]), int(anim[i]["end"]))
                    else:
                        color_fade(color, Hex(anim[0]["color"]).rgbw, int(anim[i]["time"]), int(anim[i]["start"]), int(anim[i]["end"]))
    else:
        for i in range(len(anim)):
            color = Hex(anim[i]["color"]).rgbw
            if (anim[i]["tran"] == 'jump'):
                if (anim[i]["type"] == 'bulb'):
                    requests.post('http://' + anim[i]["ip"] + '/cm?cmnd=color%20' +
                                  str(color[0]) + ',' + str(color[1]) + ',' + str(color[2]) + ',' + str(color[3]))
                elif (anim[i]["type"] == 'strip'):
                    color = Color(color[0],color[1],color[2],color[3])
                    set_sec(color, int(anim[i]["start"]), int(anim[i]["end"]))
                time.sleep(int(anim[i]["time"])/1000)
            elif (anim[i]["tran"] == 'fade'):
                if (anim[i]["type"] == 'bulb'):
                    speed = int(int(anim[i]["time"])/500)
                    if (not i == len(anim)-1):
                        color2 = Hex(anim[i+1]["color"]).rgbw
                    requests.post('http://' + anim[i]["ip"] + '/cm?cmnd=color%20' +
                                  str(color[0]) + ',' + str(color[1]) + ',' + str(color[2]) + ',' + str(color[3]))
                    requests.post('http://' + anim[i]["ip"] + '/cm?cmnd=Fade2%20' + '1')
                    requests.post('http://' + anim[i]["ip"] + '/cm?cmnd=Speed2%20' + str(speed))
                    requests.post('http://' + anim[i]["ip"] + '/cm?cmnd=color%20' +
                                  str(color2[0]) + ',' + str(color2[1]) + ',' + str(color2[2]) + ',' + str(color2[3]))
                    requests.post('http://' + anim[i]["ip"] + '/cm?cmnd=Fade2%20' + '0')
                elif (anim[i]["type"] == 'strip'):
                    if (not i == len(anim)-1):
                        color_fade(color, Hex(anim[i+1]["color"]).rgbw, int(anim[i]["time"]), int(anim[i]["start"]), int(anim[i]["end"]))
        


def init_leds(pin, count):
    global strip
    # LED strip configuration:
    LED_COUNT = count       # Number of LED pixels. (900)
    LED_PIN = pin          # GPIO pin connected to the pixels (must support PWM!). (12)
    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
    # Create PixelStrip object with appropriate configuration.
    strip = PixelStrip(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()

class index(Guy):
        
    def play_anim(self, i):
        global killpills
        animation = []
        killpills["anim" + str(i)] = True
        for step in settings["anims"][i]["order"]:
            print(step)
            for light in settings["lights"]:
                if (light["name"] == step["name"]):
                    animation.append({"type": "bulb", "ip": light["ip"],
                                      "tran": step["tran"], "time": step["time"], "color": step["color"]})
            for strip in settings["strips"]:
                if (strip["name"] == step["name"]):
                    for group in strip["groups"]:
                        if (step["group"] == group["name"]):
                            animation.append({"type": "strip", "pin": strip["pin"],
                                              "start": group["start"], "end": group["end"],
                                              "tran": step["tran"], "time": step["time"], "color": step["color"]})
        anim_thread = threading.Thread(target=run_animation, args=(animation, settings["anims"][i]["loop"], i))
        anim_thread.start()

    def stop_anim(self, i):
        global killpills
        killpills["anim" + str(i)] = False

app = index()
app.serve()

Irrelevant code chunks have been removed.

I know it's not a hardware limitation because setting the leds in the while loop directly in run_animation refreshes plently quickly.

I've tried removing extra loops and moving the color_fade call to the root of run_animation but the delay still exists. I've tried putting the set_sec code directly into color_fade which changed nothing. The only thing that made it run faster was removing the strip.show() command.

Upvotes: 1

Views: 53

Answers (0)

Related Questions