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. 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. The delay is consist as well.
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.