diff --git a/README.md b/README.md index 856bdf2..f1a3f42 100644 --- a/README.md +++ b/README.md @@ -35,4 +35,4 @@ For new settings to take effect you write: pixels.show() ``` -Library is extended verison of https://github.com/blaz-r/pico_python_ws2812b, originaly forked from https://github.com/benevpi/pico_python_ws2812b. \ No newline at end of file +Library is extended verison of https://github.com/blaz-r/pico_python_ws2812b, originally forked from https://github.com/benevpi/pico_python_ws2812b. \ No newline at end of file diff --git a/examples/colorwave.py b/examples/colorwave.py index b63e26a..7483d0d 100644 --- a/examples/colorwave.py +++ b/examples/colorwave.py @@ -2,10 +2,10 @@ # simplify working with gradients import time -from neopixel import neopixel +from neopixel import Neopixel numpix = 60 -strip = neopixel(numpix, 1, 1, "RGB") +strip = Neopixel(numpix, 1, 1, "GRB") red = (255, 0, 0) orange = (255, 50, 0) diff --git a/examples/fireflies.py b/examples/fireflies.py index aad593f..60a24b1 100644 --- a/examples/fireflies.py +++ b/examples/fireflies.py @@ -1,10 +1,10 @@ import time -import neopixel +from neopixel import Neopixel import random numpix = 60 # Number of NeoPixels # Pin where NeoPixels are connected -strip = neopixel.neopixel(numpix, 0, 0, "RGBW") +strip = Neopixel(numpix, 1, 1, "GRB") colors_rgb = [ (232, 100, 255), # Purple @@ -19,8 +19,8 @@ colors_rgbw = [color+tuple([0]) for color in colors_rgb] colors_rgbw.append((0, 0, 0, 255)) # uncomment colors_rgbw if you have RGBW strip -# colors = colors_rgb -colors = colors_rgbw +colors = colors_rgb +# colors = colors_rgbw max_len=20 min_len = 5 diff --git a/examples/rainbow.py b/examples/rainbow.py index 751263e..1ac2e74 100644 --- a/examples/rainbow.py +++ b/examples/rainbow.py @@ -1,8 +1,8 @@ import time -from neopixel import neopixel +from neopixel import Neopixel numpix = 60 -strip = neopixel(numpix, 0, 0, "RGBW") +strip = Neopixel(numpix, 0, 0, "RGBW") red = (255, 0, 0) orange = (255, 165, 0) @@ -17,7 +17,7 @@ colors_rgb = (red, orange, yellow, green, blue, indigo, violet) colors_rgbw = [color+tuple([0]) for color in colors_rgb] colors_rgbw.append((0, 0, 0, 255)) -# uncomment colors_rgbw if you have RGBW strip +# uncomment colors_rgb if you have RGB strip # colors = colors_rgb colors = colors_rgbw diff --git a/neopixel.py b/neopixel.py index a0de228..9f76fd8 100644 --- a/neopixel.py +++ b/neopixel.py @@ -33,18 +33,32 @@ def sk6812(): wrap() -# 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 # you could put in delay=0 (or a lower delay) -class neopixel: - def __init__(self, num_leds, state_machine, pin, mode="RGB", delay=0.001): +# +# Class supports different order of individual colors (GRB, RGB, WRGB, GWRB ...). In order to achieve +# this, we need to flip the indexes: in 'RGBW', 'R' is on index 0, but we need to shift it left by 3 * 8bits, +# so in it's inverse, 'WBGR', it has exactly right index. Since micropython doesn't have [::-1] and recursive rev() +# isn't too efficient we simply do that by XORing (operand ^) each index with 3 (0b11) to make this flip. +# When dealing with just 'RGB' (3 letter string), this means same but reduced by 1 after XOR!. +# Example: in 'GRBW' we want final form of 0bGGRRBBWW, meaning G with index 0 needs to be shifted 3 * 8bit -> +# 'G' on index 0: 0b00 ^ 0b11 -> 0b11 (3), just as we wanted. +# Same hold for every other index (and - 1 at the end for 3 letter strings). + +class Neopixel: + def __init__(self, num_leds, state_machine, pin, mode="RGB", delay=0.001): self.pixels = array.array("I", [0 for _ in range(num_leds)]) - self.mode = set(mode) - # RGBW uses different PIO state machine configuration + self.mode = set(mode) # set for better performance if 'W' in self.mode: + # RGBW uses different PIO state machine configuration self.sm = rp2.StateMachine(state_machine, sk6812, freq=8000000, sideset_base=Pin(pin)) + self.shift = {'R': (mode.index('R') ^ 3) * 8, 'G': (mode.index('G') ^ 3) * 8, + 'B': (mode.index('B') ^ 3) * 8, 'W': (mode.index('W') ^ 3) * 8} else: self.sm = rp2.StateMachine(state_machine, ws2812, freq=8000000, sideset_base=Pin(pin)) + self.shift = {'R': ((mode.index('R') ^ 3) - 1) * 8, 'G': ((mode.index('G') ^ 3) - 1) * 8, + 'B': ((mode.index('B') ^ 3) - 1) * 8, 'W': 0} self.sm.active(1) self.num_leds = num_leds self.delay = delay @@ -90,17 +104,17 @@ class neopixel: # Set red, green and blue value of pixel on position # Function accepts (r, g, b) tuple or individual rgb values3 def set_pixel(self, pixel_num, rgb_w): + pos = self.shift red = round(rgb_w[0] * (self.brightness() / 255)) green = round(rgb_w[1] * (self.brightness() / 255)) blue = round(rgb_w[2] * (self.brightness() / 255)) + white = 0 # if it's (r, g, b, w) if len(rgb_w) == 4 and 'W' in self.mode: white = round(rgb_w[3] * (self.brightness() / 255)) - # bits are of form 0bGGRRBBWW - self.pixels[pixel_num] = green << 24 | red << 16 | blue << 8 | white - else: - self.pixels[pixel_num] = green << 16 | red << 8 | blue + + self.pixels[pixel_num] = white << pos['W'] | blue << pos['B'] | red << pos['R'] | green << pos['G'] # Rotate pixels to the left def rotate_left(self, num_of_pixels):