Porównaj commity

...

2 Commity

Autor SHA1 Wiadomość Data
Blaž Rolih 3f50b85c5f
Linked documentation in readme 2022-07-10 15:23:50 +02:00
blaz-r a36f379c3a Added docstrings to functions 2022-07-10 15:15:18 +02:00
2 zmienionych plików z 120 dodań i 41 usunięć

Wyświetl plik

@ -3,6 +3,10 @@ a library for using ws2812b and sk6812 leds (aka neopixels) with Raspberry Pi Pi
![example](https://github.com/blaz-r/pi_pico_neopixel/blob/main/pico_rgbw_rgb.jpg) ![example](https://github.com/blaz-r/pi_pico_neopixel/blob/main/pico_rgbw_rgb.jpg)
### Detailed documentation can be found on [Wiki page](https://github.com/blaz-r/pi_pico_neopixel/wiki).
## Quick start guide
You'll first need to save the neopixel.py file to your device (for example, open it in Thonny and go file > save as and select MicroPython device. Give it the same name). Once it's there, you can import it into your code. You'll first need to save the neopixel.py file to your device (for example, open it in Thonny and go file > save as and select MicroPython device. Give it the same name). Once it's there, you can import it into your code.
## Initialization ## Initialization
@ -43,7 +47,7 @@ For new settings to take effect you write:
pixels.show() pixels.show()
``` ```
For more examples, check [examples folder](https://github.com/blaz-r/pi_pico_neopixel/tree/main/examples). For more examples, check [examples folder](https://github.com/blaz-r/pi_pico_neopixel/tree/main/examples) and [documentation](https://github.com/blaz-r/pi_pico_neopixel/wiki).
## HSV colors ## HSV colors

Wyświetl plik

@ -2,6 +2,7 @@ import array, time
from machine import Pin from machine import Pin
import rp2 import rp2
# PIO state machine for RGB. Pulls 24 bits (rgb -> 3 * 8bit) automatically # PIO state machine for RGB. Pulls 24 bits (rgb -> 3 * 8bit) automatically
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24) @rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812(): def ws2812():
@ -14,9 +15,10 @@ def ws2812():
jmp(not_x, "do_zero") .side(1) [T1 - 1] jmp(not_x, "do_zero") .side(1) [T1 - 1]
jmp("bitloop") .side(1) [T2 - 1] jmp("bitloop") .side(1) [T2 - 1]
label("do_zero") label("do_zero")
nop().side(0) [T2 - 1] nop() .side(0) [T2 - 1]
wrap() wrap()
# PIO state machine for RGBW. Pulls 32 bits (rgbw -> 4 * 8bit) automatically # PIO state machine for RGBW. Pulls 32 bits (rgbw -> 4 * 8bit) automatically
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=32) @rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=32)
def sk6812(): def sk6812():
@ -32,14 +34,18 @@ def sk6812():
nop() .side(0) [T2 - 1] nop() .side(0) [T2 - 1]
wrap() wrap()
# we need this because Micropython can't construct slice objects directly, only by # we need this because Micropython can't construct slice objects directly, only by
# way of supporting slice notation. # way of supporting slice notation.
# So, e.g. slice_maker[1::4] gives a slice(1,None,4) object. # So, e.g. slice_maker[1::4] gives a slice(1,None,4) object.
class slice_maker_class: class slice_maker_class:
def __getitem__(self,slc): def __getitem__(self, slc):
return slc return slc
slice_maker = slice_maker_class() slice_maker = slice_maker_class()
# Delay here is the reset time. You need a pause to reset the LED strip back to the initial LED # Delay here is the reset time. You need a pause to reset the LED strip back to the initial LED
# however, if you have quite a bit of processing to do before the next time you update the strip # however, if you have quite a bit of processing to do before the next time you update the strip
# you could put in delay=0 (or a lower delay) # you could put in delay=0 (or a lower delay)
@ -56,7 +62,7 @@ slice_maker = slice_maker_class()
class Neopixel: class Neopixel:
# Micropython doesn't implement __slots__, but it's good to have a place # Micropython doesn't implement __slots__, but it's good to have a place
# to describe the data members... # to describe the data members...
#__slots__ = [ # __slots__ = [
# 'num_leds', # number of LEDs # 'num_leds', # number of LEDs
# 'pixels', # array.array('I') of raw data for LEDs # 'pixels', # array.array('I') of raw data for LEDs
# 'mode', # mode 'RGB' etc # 'mode', # mode 'RGB' etc
@ -65,9 +71,19 @@ class Neopixel:
# 'shift', # shift amount for each component, in a tuple for (R,B,G,W) # 'shift', # shift amount for each component, in a tuple for (R,B,G,W)
# 'delay', # delay amount # 'delay', # delay amount
# 'brightnessvalue', # brightness scale factor 1..255 # 'brightnessvalue', # brightness scale factor 1..255
#] # ]
def __init__(self, num_leds, state_machine, pin, mode="RGB", delay=0.0001): def __init__(self, num_leds, state_machine, pin, mode="RGB", delay=0.0001):
"""
Constructor for library class
:param num_leds: number of leds on your led-strip
:param state_machine: id of PIO state machine used
:param pin: pin on which data line to led-strip is connected
:param mode: [default: "RGB"] mode and order of bits representing the color value.
This can be any order of RGB or RGBW (neopixels are usually GRB)
:param delay: [default: 0.0001] delay used for latching of leds when sending data
"""
self.pixels = array.array("I", [0] * num_leds) self.pixels = array.array("I", [0] * num_leds)
self.mode = mode self.mode = mode
self.W_in_mode = 'W' in mode self.W_in_mode = 'W' in mode
@ -86,8 +102,14 @@ class Neopixel:
self.delay = delay self.delay = delay
self.brightnessvalue = 255 self.brightnessvalue = 255
# Set the overal value to adjust brightness when updating leds
def brightness(self, brightness=None): def brightness(self, brightness=None):
"""
Set the overall value to adjust brightness when updating leds
or return class brightnessvalue if brightness is None
:param brightness: [default: None] Value of brightness on interval 1..255
:return: class brightnessvalue member or None
"""
if brightness is None: if brightness is None:
return self.brightnessvalue return self.brightnessvalue
else: else:
@ -97,9 +119,17 @@ class Neopixel:
brightness = 255 brightness = 255
self.brightnessvalue = brightness self.brightnessvalue = brightness
# Create a gradient with two RGB colors between "pixel1" and "pixel2" (inclusive) def set_pixel_line_gradient(self, pixel1, pixel2, left_rgb_w, right_rgb_w, how_bright=None):
# Function accepts two (r, g, b) / (r, g, b, w) tuples """
def set_pixel_line_gradient(self, pixel1, pixel2, left_rgb_w, right_rgb_w, how_bright = None): Create a gradient with two RGB colors between "pixel1" and "pixel2" (inclusive)
:param pixel1: Index of starting pixel (inclusive)
:param pixel2: Index of ending pixel (inclusive)
:param left_rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing starting color
:param right_rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing ending color
:param how_bright: [default: None] Brightness of current interval. If None, use global brightness value
:return: None
"""
if pixel2 - pixel1 == 0: if pixel2 - pixel1 == 0:
return return
right_pixel = max(pixel1, pixel2) right_pixel = max(pixel1, pixel2)
@ -124,18 +154,30 @@ class Neopixel:
else: else:
self.set_pixel(left_pixel + i, (red, green, blue), how_bright) self.set_pixel(left_pixel + i, (red, green, blue), how_bright)
# Set an array of pixels starting from "pixel1" to "pixel2" (inclusive) to the desired color. def set_pixel_line(self, pixel1, pixel2, rgb_w, how_bright=None):
# Function accepts (r, g, b) / (r, g, b, w) tuple """
def set_pixel_line(self, pixel1, pixel2, rgb_w, how_bright = None): Set an array of pixels starting from "pixel1" to "pixel2" (inclusive) to the desired color.
:param pixel1: Index of starting pixel (inclusive)
:param pixel2: Index of ending pixel (inclusive)
:param rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing color to be used
:param how_bright: [default: None] Brightness of current interval. If None, use global brightness value
:return: None
"""
if pixel2 >= pixel1: if pixel2 >= pixel1:
self.set_pixel(slice_maker[pixel1:pixel2 + 1], rgb_w, how_bright) self.set_pixel(slice_maker[pixel1:pixel2 + 1], rgb_w, how_bright)
# Set red, green and blue value of pixel on position <pixel_num> def set_pixel(self, pixel_num, rgb_w, how_bright=None):
# Function accepts (r, g, b) / (r, g, b, w) tuple """
# pixel_num may be a 'slice' object, and then the operation is applied Set red, green and blue (+ white) value of pixel on position <pixel_num>
# to all pixels implied by the slice (most useful when called via pixel_num may be a 'slice' object, and then the operation is applied
# __setitem__) to all pixels implied by the slice (most useful when called via __setitem__)
def set_pixel(self, pixel_num, rgb_w, how_bright = None):
:param pixel_num: Index of pixel to be set or slice object representing multiple leds
:param rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing color to be used
:param how_bright: [default: None] Brightness of current interval. If None, use global brightness value
:return: None
"""
if how_bright is None: if how_bright is None:
how_bright = self.brightness() how_bright = self.brightness()
sh_R, sh_G, sh_B, sh_W = self.shift sh_R, sh_G, sh_B, sh_W = self.shift
@ -157,22 +199,34 @@ class Neopixel:
else: else:
self.pixels[pixel_num] = pix_value self.pixels[pixel_num] = pix_value
# if npix is a Neopixel object,
# npix[10] = (0,255,0) # <- sets #10 to green
# npix[15:21] = (255,0,0) # <- sets 16,17 .. 20 to red
# npix[21:29:2] = (0,0,255) # <- sets 21,23,25,27 to blue
# npix[1::2] = (0,0,0) # <- sets all odd pixels to 'off'
# (the 'slice' cases pass idx as a 'slice' object, and
# set_pixel processes the slice)
def __setitem__(self, idx, rgb_w): def __setitem__(self, idx, rgb_w):
self.set_pixel(idx,rgb_w) """
if npix is a Neopixel object,
npix[10] = (0,255,0) # <- sets #10 to green
npix[15:21] = (255,0,0) # <- sets 16,17 .. 20 to red
npix[21:29:2] = (0,0,255) # <- sets 21,23,25,27 to blue
npix[1::2] = (0,0,0) # <- sets all odd pixels to 'off'
(the 'slice' cases pass idx as a 'slice' object, and
set_pixel processes the slice)
:param idx: Index can either be indexing number or slice
:param rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing color to be used
:return:
"""
self.set_pixel(idx, rgb_w)
# Converts HSV color to rgb tuple and returns it
# Function accepts integer values for <hue>, <saturation> and <value>
# The logic is almost the same as in Adafruit NeoPixel library:
# https://github.com/adafruit/Adafruit_NeoPixel so all the credits for that
# go directly to them (license: https://github.com/adafruit/Adafruit_NeoPixel/blob/master/COPYING)
def colorHSV(self, hue, sat, val): def colorHSV(self, hue, sat, val):
"""
Converts HSV color to rgb tuple and returns it.
The logic is almost the same as in Adafruit NeoPixel library:
https://github.com/adafruit/Adafruit_NeoPixel so all the credits for that
go directly to them (license: https://github.com/adafruit/Adafruit_NeoPixel/blob/master/COPYING)
:param hue: Hue component. Should be on interval 0..65535
:param sat: Saturation component. Should be on interval 0..255
:param val: Value component. Should be on interval 0..255
:return: (r, g, b) tuple
"""
if hue >= 65536: if hue >= 65536:
hue %= 65536 hue %= 65536
@ -216,22 +270,35 @@ class Neopixel:
return r, g, b return r, g, b
def rotate_left(self, num_of_pixels=None):
"""
Rotate <num_of_pixels> pixels to the left
# Rotate <num_of_pixels> pixels to the left :param num_of_pixels: Number of pixels to be shifted to the left. If None, it shifts for 1.
def rotate_left(self, num_of_pixels = None): :return: None
"""
if num_of_pixels is None: if num_of_pixels is None:
num_of_pixels = 1 num_of_pixels = 1
self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels]
# Rotate <num_of_pixels> pixels to the right def rotate_right(self, num_of_pixels=None):
def rotate_right(self, num_of_pixels = None): """
Rotate <num_of_pixels> pixels to the right
:param num_of_pixels: Number of pixels to be shifted to the right. If None, it shifts for 1.
:return: None
"""
if num_of_pixels is None: if num_of_pixels is None:
num_of_pixels = 1 num_of_pixels = 1
num_of_pixels = -1 * num_of_pixels num_of_pixels = -1 * num_of_pixels
self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels] self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels]
# Update pixels
def show(self): def show(self):
"""
Send data to led-strip, making all changes on leds have an effect.
This method should be used after every method that changes the state of leds or after a chain of changes.
:return: None
"""
# If mode is RGB, we cut 8 bits of, otherwise we keep all 32 # If mode is RGB, we cut 8 bits of, otherwise we keep all 32
cut = 8 cut = 8
if self.W_in_mode: if self.W_in_mode:
@ -241,13 +308,21 @@ class Neopixel:
sm_put(pixval, cut) sm_put(pixval, cut)
time.sleep(self.delay) time.sleep(self.delay)
# Set all pixels to given rgb values def fill(self, rgb_w, how_bright=None):
# Function accepts (r, g, b) / (r, g, b, w) """
def fill(self, rgb_w, how_bright = None): Fill the entire strip with color rgb_w
:param rgb_w: Tuple of form (r, g, b) or (r, g, b, w) representing color to be used
:param how_bright: [default: None] Brightness of current interval. If None, use global brightness value
:return: None
"""
# set_pixel over all leds. # set_pixel over all leds.
self.set_pixel(slice_maker[:], rgb_w, how_bright) self.set_pixel(slice_maker[:], rgb_w, how_bright)
# Clear the strip
def clear(self): def clear(self):
self.pixels = array.array("I", [0] * self.num_leds) """
Clear the entire strip, i.e. set every led color to 0.
:return: None
"""
self.pixels = array.array("I", [0] * self.num_leds)