DotStar LED Strips
Download all scripts: 7-dotstar_led_strips.zip
DotStars |
NeoPixels |
|
|---|---|---|
Interface |
▽ 4-wire |
▲ 3-wire |
Timing |
▲ flexible, standard SPI |
▽ strict, custom |
Data rate |
▲ flexible up to 32 MHz |
▽ fixed to 800 kHz |
PWM rate |
▲ 19.2 kHz |
▽ 400 Hz |
Price 1 |
▽ ~ 30 EUR/m |
▲ ~ 20 EUR/m |
LED colors |
▽ RGB, W |
▲ RGB, RGBW, W |
LEDs |
APA102, APA102C, SK9822 |
WS2812b, WS2813, SK6812, SK6822, APA104 |
Data per LED |
4 Bytes |
3 Bytes |
Max. LEDs 2 |
160.000 |
5.333 |
References
APA Electronic co., Ltd APA102C
World Semi WS2812B
71-dotstar_blink_minimal.py
#!/usr/bin/env python3
import Adafruit_GPIO.SPI as SPI
from itertools import chain
import time
led_count = 8 # The number of LEDs to be controlled
brightness = 1 # 5-bit value (= 0 .. 31)
# Create a nested array for use as off-screen frame buffer [^1]
led_frame = [0b11100000 + brightness, 0, 0, 0]
leds = [led_frame] * led_count
# Setup hardware SPI connection (10 = MOSI, 11 = SCLK)
spi = SPI.SpiDev(1, 0, 8000000) # Bus 1, chip select 0, clock speed 8 MHz
def set_color(rgb = 0, led_ids = None):
if type(led_ids) == int: # Single led
led_ids = range(led_ids, led_ids + 1)
elif type(led_ids) == list or type(led_ids) == tuple or type(led_ids) == range: # Range of leds
pass
else: # All leds
led_ids = range(led_count)
if type(rgb) == int:
red, green, blue = rgb >> 16, rgb >> 8 & 0xff, rgb & 0xff
elif type(rgb) == list or type(rgb) == tuple:
red, green, blue = rgb
for led_id in led_ids:
leds[led_id] = [0b11100000 + brightness, blue, green, red]
def display():
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000] # Start frame: 4 Bytes of 0's
led_frames = list(chain.from_iterable(leds)) # Flatten nested list (= list containing lists)
end_frame = [0x11111111] * ((led_count + 15) // 16) # End frame: 1 bit for every two LEDs, rounded up to bytes
spi.write(start_frame + led_frames + end_frame)
set_color() # Turn all LEDs in off-screen frame buffer off
try:
# led_ids = 1 # A single led
# led_ids = (0, 3, 4, 7, 8, 9) # Multiple leds by tuple or array with ids
# led_ids = range(2, led_count) # Multiple leds by range
led_ids = range(0, led_count, 2) # Every second led
# led_ids = None # All leds
while True:
set_color(0xff0000, led_ids) # Set color of selected LEDs in off-screen frame buffer to red
display() # Write off-screen frame buffer to LED strip
time.sleep(.5)
set_color(0x000000, led_ids) # Turn selected LEDs in off-screen frame buffer off (= set color black)
display() # Write off-screen frame buffer to LED strip
time.sleep(.5)
except KeyboardInterrupt: # Control-C was pressed
pass
set_color() # Turn all LEDs in off-screen frame buffer off
display() # Write off-screen frame buffer to LED strip
spi.close() # Close SPI connection
print('\nBye, bye.')
"""
DotStar LED strips make it easy to indvidually control a large amount of RGB LEDs. They require only a 4 wire connection to the first LED, all others are connected to each other.
The 4 connections are
VCC ... +5V power supply
GND ... Ground
CI ... Clock input
DI ... Data input
The LEDs can be individually addressed using an SPI (Serial Peripheral Interface) connection using the following protocol:
Start frame: 4 bytes of 0's
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000]
LED frames: 4 bytes
led_frame = [0b11100000 + brightness, blue, red, green]
End frame: for every 2 LEDs an additional clock cycle has to be added. This can be done by sending additional data bytes.
end_frame = [0x11111111] * ((led_count + 31) // 16)
[^1]
The off-screen frame buffer is a list of all LEDs
[ led_0,
led_1,
led_2,
... ]
where each led_n is a list itself
led_n = [brightness, blue, green, red]
which results in a nested list (a list containing lists)
[ [brightness_0, blue_0, green_0, red_0],
[brightness_1, blue_1, green_1, red_1],
[brightness_2, blue_2, green_2, red_2],
... ]
References
----------
APA 102C datasheet: http://neon-world.com/uploads/soft/20161130/1480487678.pdf
DotStars & NeoPixels: https://learn.adafruit.com/adafruit-dotstar-leds?view=all
"""
72-dotstar_blink_w_class.py
#!/usr/bin/env python3
import Adafruit_GPIO.SPI as SPI
import time
class LED_Strip():
def __init__(self, led_count, brightness = 1):
self.led_count = led_count
self.brightness = min(31, brightness) # 5-bit value (= 0 .. 31)
# Create an array for use as off-screen frame buffer
led_frame = [0b11100000 + brightness, 0, 0, 0]
self.leds = [led_frame] * led_count
# Setup hardware SPI connection (10 = MOSI, 11 = SCLK)
self.spi = SPI.SpiDev(1, 0, 8000000) # Bus 1, chip select 0, clock speed 8 MHz
self.clear()
self.display()
def set_color(self, rgb = 0, led_ids = None):
if type(led_ids) == int: # Single led
led_ids = range(led_ids, led_ids + 1)
elif type(led_ids) == list or type(led_ids) == tuple or type(led_ids) == range: # Range of leds
pass
else: # All leds
led_ids = range(self.led_count)
red, green, blue = rgb >> 16, rgb >> 8 & 0xff, rgb & 0xff
for led_id in led_ids:
self.leds[led_id] = [0b11100000 + self.brightness, blue, green, red]
def display(self):
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000] # Start frame: 4 Bytes of 0's
led_frames = [led_data for led in self.leds for led_data in led]
end_frame = [0x11111111] * ((self.led_count + 31) // 16) # End frame: 1 bit for every two LEDs, rounded up to bytes
self.spi.write(start_frame + led_frames + end_frame)
def clear(self):
self.set_color() # Turn all LEDs in off-screen frame buffer off
def cleanup(self):
self.set_color() # Turn all LEDs in off-screen frame buffer off
self.display() # Write off-screen frame buffer to LED strip
self.spi.close()
led_count = 8
led_strip = LED_Strip(led_count)
try:
# led_ids = 1 # A single led
# led_ids = (0, 3, 4, 7, 8, 9) # Multiple leds by tuple or array with ids
# led_ids = range(2, 8) # Multiple leds by range
led_ids = range(0, led_count, 2) # Every second led
# led_ids = None # All leds
while True:
led_strip.set_color(0xff0000, led_ids)
led_strip.display()
time.sleep(.5)
led_strip.set_color(0x000000, led_ids)
led_strip.display()
time.sleep(.5)
except KeyboardInterrupt: # Control-C was pressed
pass
led_strip.cleanup()
print('\nBye, bye.')
"""
DotStar LED strips make it easy to indvidually control a large amount of RGB LEDs. They require only a 4 wire connection to the first LED, all others are connected to each other.
The 4 connections are
VCC ... +5V power supply
GND ... Ground
CI ... Clock input
DI ... Data input
The LEDs can be individually addressed using an SPI (Serial Peripheral Interface) connection using the following protocol:
Start frame: 4 bytes of 0's
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000]
LED frames: 4 bytes
led_frame = [0b11100000 + brightness, blue, red, green]
End frame: for every 2 LEDs an additional clock cycle has to be added. This can be done by sending additional data bytes.
end_frame = [0x11111111] * ((led_count + 31) // 16)
References
----------
APA 102C datasheet: http://neon-world.com/uploads/soft/20161130/1480487678.pdf
DotStars & NeoPixels: https://learn.adafruit.com/adafruit-dotstar-leds?view=all
"""
73-dotstar_blink_w_external_class.py
#!/usr/bin/env python3
import dotstar
import time
led_count = 8
led_strip = dotstar.LED_Strip(led_count)
try:
# led_ids = 1 # A single led
# led_ids = (0, 3, 4, 7, 8, 9) # Multiple leds by tuple or array with ids
# led_ids = range(2, 8) # Multiple leds by range
led_ids = range(0, led_count, 2) # Every second led
# led_ids = None # All leds
while True:
led_strip.set_color(0xff0000, led_ids)
led_strip.display()
time.sleep(.5)
led_strip.set_color(0x000000, led_ids)
led_strip.display()
time.sleep(.5)
except KeyboardInterrupt: # Control-C was pressed
pass
led_strip.cleanup()
print('\nBye, bye.')
"""
DotStar LED strips make it easy to indvidually control a large amount of RGB LEDs. They require only a 4 wire connection to the first LED, all others are connected to each other.
The 4 connections are
VCC ... +5V power supply
GND ... Ground
CI ... Clock input
DI ... Data input
The LEDs can be individually addressed using an SPI (Serial Peripheral Interface) connection using the following protocol:
Start frame: 4 bytes of 0's
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000]
LED frames: 4 bytes
led_frame = [0b11100000 + brightness, blue, red, green]
End frame: for every 2 LEDs an additional clock cycle has to be added. This can be done by sending additional data bytes.
end_frame = [0x11111111] * ((led_count + 31) // 16)
References
----------
APA 102C datasheet: http://neon-world.com/uploads/soft/20161130/1480487678.pdf
DotStars & NeoPixels: https://learn.adafruit.com/adafruit-dotstar-leds?view=all
"""
dotstar/__init__.py
#!/usr/bin/env python3
from .led_strip import *
dotstar/led_strip.py
#!/usr/bin/env python3
import Adafruit_GPIO.SPI as SPI
from itertools import chain
class LED_Strip():
BLEND_MODE_OVERWRITE = 0
BLEND_MODE_ADD = 1
BLEND_MODE_MULTIPLY = 2
def __init__(self, led_count, brightness = 1):
self.led_count = led_count
self.brightness = max(0, min(31, brightness)) # 5-bit value (= 0 .. 31)
# Setup hardware SPI connection (10 = MOSI, 11 = SCLK)
self.spi = SPI.SpiDev(1, 0, 8000000) # Bus 1, chip select 0, clock speed 8 MHz
self.clear() # Creates an array for use as off-screen frame buffer
self.display()
def set_color(self, rgb = 0, led_ids = None, blend_mode = BLEND_MODE_OVERWRITE):
if type(led_ids) == int: # Single led
led_ids = range(led_ids, led_ids + 1)
elif type(led_ids) == list or type(led_ids) == tuple or type(led_ids) == range: # Range of leds
pass
else: # All leds
led_ids = range(self.led_count)
if type(rgb) == int:
red, green, blue = rgb >> 16, rgb >> 8 & 0xff, rgb & 0xff
elif type(rgb) == list or type(rgb) == tuple:
red, green, blue = rgb
for led_id in led_ids:
if blend_mode == self.BLEND_MODE_OVERWRITE:
self.leds[led_id] = [0b11100000 + self.brightness, blue, green, red]
elif blend_mode == self.BLEND_MODE_ADD:
self.leds[led_id] = [max(0, min(255, color_1_component + color_2_component))
for color_1_component, color_2_component in zip(self.leds[led_id], [0, blue, green, red])]
elif blend_mode == self.BLEND_MODE_MULTIPLY:
self.leds[led_id] = [max(0, min(255, int(color_1_component * color_2_component / 255)))
for color_1_component, color_2_component in zip(self.leds[led_id], [255, blue, green, red])]
def display(self):
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000] # Start frame: 4 Bytes of 0's
led_frames = list(chain.from_iterable(self.leds)) # Flatten nested list
end_frame = [0x11111111] * ((self.led_count + 15) // 16) # End frame: 1 bit for every two LEDs, rounded up to bytes
frames = start_frame + led_frames + end_frame
# spi.write is limited to 4096 bytes (= 1007 LEDs)
chunks = [frames[chunk_start : chunk_start + 4096] for chunk_start in range(0, len(frames), 4096)]
for chunk in chunks:
self.spi.write(chunk)
def clear(self):
led_frame = [0b11100000 + self.brightness, 0, 0, 0]
self.leds = [led_frame] * self.led_count
def cleanup(self):
self.clear()
self.display()
self.spi.close()
74-dotstar_sweep.py
#!/usr/bin/env python3
import dotstar
import time
led_count = 8
led_strip = dotstar.LED_Strip(10)
try:
while True:
for led_id in range(led_count - 1): # Iterate from 0 to 8
led_strip.set_color(0xff0000, led_id)
led_strip.display()
time.sleep(.05)
led_strip.set_color(0x000000, led_id)
led_strip.display()
for led_id in range(led_count - 1, 0, -1): # Iterate from 9 to 1
led_strip.set_color(0xff0000, led_id)
led_strip.display()
time.sleep(.05)
led_strip.set_color(0x000000, led_id)
led_strip.display()
except KeyboardInterrupt: # Control-C was pressed
pass
led_strip.cleanup()
print('\nBye, bye.')
"""
DotStar LED strips make it easy to indvidually control a large amount of RGB LEDs. They require only a 4 wire connection to the first LED, all others are connected to each other.
The 4 connections are
VCC ... +5V power supply
GND ... Ground
CI ... Clock input
DI ... Data input
The LEDs can be individually addressed using an SPI (Serial Peripheral Interface) connection using the following protocol:
Start frame: 4 bytes of 0's
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000]
LED frames: 4 bytes
led_frame = [0b11100000 + brightness, blue, red, green]
End frame: for every 2 LEDs an additional clock cycle has to be added. This can be done by sending additional data bytes.
end_frame = [0x11111111] * ((led_count + 31) // 16)
References
----------
APA 102C datasheet: http://neon-world.com/uploads/soft/20161130/1480487678.pdf
DotStars & NeoPixels: https://learn.adafruit.com/adafruit-dotstar-leds?view=all
"""
75-dotstar_color_cycle.py
#!/usr/bin/env python3
import dotstar
import time, colorsys
led_count = 8
led_strip = dotstar.LED_Strip(led_count)
try:
led_ids = range(0, led_count, 2) # Every second led
cycle_duration = 2 # Seconds for a full color cycle
resolution = 1 # Degrees resolution
while True:
for hue in range(0, 360, resolution):
# Convert the hue value to the r, g, b values
r, g, b = colorsys.hsv_to_rgb(hue / 360.0, 1, 1) # The range of the r, g, b values is 0.0 .. 1.0
led_strip.set_color([int(255 * r), int(255 * g), int(255 * b)], led_ids)
led_strip.display()
time.sleep(cycle_duration / (360 / resolution))
except KeyboardInterrupt: # Control-C was pressed
pass
led_strip.cleanup()
print('\nBye, bye.')
"""
DotStar LED strips make it easy to indvidually control a large amount of RGB LEDs. They require only a 4 wire connection to the first LED, all others are connected to each other.
The 4 connections are
VCC ... +5V power supply
GND ... Ground
CI ... Clock input
DI ... Data input
The LEDs can be individually addressed using an SPI (Serial Peripheral Interface) connection using the following protocol:
Start frame: 4 bytes of 0's
start_frame = [0b00000000, 0b00000000, 0b00000000, 0b00000000]
LED frames: 4 bytes
led_frame = [0b11100000 + brightness, blue, red, green]
End frame: for every 2 LEDs an additional clock cycle has to be added. This can be done by sending additional data bytes.
end_frame = [0x11111111] * ((led_count + 31) // 16)
References
----------
APA 102C datasheet: http://neon-world.com/uploads/soft/20161130/1480487678.pdf
DotStars & NeoPixels: https://learn.adafruit.com/adafruit-dotstar-leds?view=all
"""
76-dotstar_rainbow_blink_w_afterglow.py
#!/usr/bin/env python3
import dotstar
import colorsys, time
led_count = 8
led_strip = dotstar.LED_Strip(led_count)
try:
# led_ids = 1 # A single led
# led_ids = (0, 3, 4, 7, 8, 9) # Multiple leds by tuple or array with ids
# led_ids = range(2, 8) # Multiple leds by range
led_ids = range(0, led_count, 2) # Every second led
# led_ids = None # All leds
afterglow_duration = 2
step_count = 100
step_size = int(255 * (1 / 255) ** (1 / step_count))
hue = 0
while True:
r, g, b = colorsys.hsv_to_rgb(hue / 360.0, 1, 1)
led_strip.set_color((int(255 * r), int(255 * g), int(255 * b)), led_ids)
led_strip.display()
hue += 30
for i in range(step_count):
led_strip.set_color((step_size, step_size, step_size), blend_mode = led_strip.BLEND_MODE_MULTIPLY)
led_strip.display()
time.sleep(afterglow_duration / step_count)
except KeyboardInterrupt: # Control-C was pressed
pass
led_strip.cleanup()
print('\nBye, bye.')
77-dotstar_rainbow_sweep_w_afterglow.py
#!/usr/bin/env python3
import dotstar
import time, colorsys
led_count = 8
led_strip = dotstar.LED_Strip(led_count)
try:
step_count = 5 # The number of steps after color * step_size = 0 [^1]
step_size = int(255 * (1 / 255) ** (1 / step_count)) # The resulting step_size
hue = 0
while True:
for led_id in range(led_count - 1):
r, g, b = colorsys.hsv_to_rgb(hue / 360.0, 1, 1)
led_strip.set_color((step_size, step_size, step_size), blend_mode = led_strip.BLEND_MODE_MULTIPLY)
led_strip.set_color((int(255 * r), int(255 * g), int(255 * b)), led_id)
led_strip.display()
time.sleep(.05)
hue += 5
for led_id in range(led_count - 1, 0, -1):
r, g, b = colorsys.hsv_to_rgb(hue / 360.0, 1, 1)
led_strip.set_color((step_size, step_size, step_size), blend_mode = led_strip.BLEND_MODE_MULTIPLY)
led_strip.set_color((int(255 * r), int(255 * g), int(255 * b)), led_id)
led_strip.display()
time.sleep(.05)
hue += 5
except KeyboardInterrupt: # Control-C was pressed
pass
led_strip.cleanup()
print('\nBye, bye.')
"""
[^1]
Due to rounding errors the number of steps might be less
E.g.
step_count = 15 --> step_size = 176
step | color
-----+------
0 | 176
1 | 121
2 | 83
3 | 57
4 | 39
5 | 26
6 | 17
7 | 11
8 | 7
9 | 4
10 | 2
11 | 1
12 | 0
13 | 0
14 | 0
print('step_count = {} --> step_size = {}\n'.format(step_count, step_size))
print('step | color \n-----+------')
color = 255
for step in range(step_count):
color = int(color * step_size / 255)
print(' {:>3} | {:>3}'.format(step, color))
"""