diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..600d2d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/examples/plasma/README.md b/examples/plasma/README.md new file mode 100644 index 0000000..de89932 --- /dev/null +++ b/examples/plasma/README.md @@ -0,0 +1,34 @@ +# Plasma 2040 Micropython Examples + +These are micropython examples for the Pimoroni [Plasma 2040](https://shop.pimoroni.com/products/plasma-2040), a RP2040-based driver board for addressable LED strips. + +- [Effect Examples](#effect-examples) + - [Pulse Wave](#pulse-wave) + - [Binary Counter](#binary-counter) + - [Rainbow Wave](#rainbow-wave) + + +## Effect Examples + +### Pulse Wave +[effects/pulse_wave.py](effects/pulse_wave.py) + +Play a wave of pulses on Plasma 2040's strip output. +This is an *experimental* feature, that can struggle when +complex effects with high update rates are applied to many LEDs. + + +### Binary Counter +[effects/binary_counter.py](effects/binary_counter.py) + +Play a binary counter effect on Plasma 2040's strip output. +This is an *experimental* feature, that can struggle when +complex effects with high update rates are applied to many LEDs. + + +### Rainbow Wave +[effects/rainbow_wave.py](effects/rainbow_wave.py) + +Play a rainbow wave effect on Plasma 2040's strip output. +This is an *experimental* feature, that can struggle when +complex effects with high update rates are applied to many LEDs. diff --git a/examples/plasma/examples/binary_counter.py b/examples/plasma/examples/binary_counter.py new file mode 100644 index 0000000..9ecb8ea --- /dev/null +++ b/examples/plasma/examples/binary_counter.py @@ -0,0 +1,59 @@ +import plasma +from plasma import plasma2040 +from picofx import StripPlayer +from picofx.mono import BinaryCounterFX +from pimoroni import Button + +""" +Play a binary counter effect on Plasma 2040's strip output. +This is an *experimental* feature, that can struggle when +complex effects with high update rates are applied to many LEDs. + +Press "Boot" to exit the program. +""" + +# Constants +NUM_LEDS = 60 # How many LEDs are on the connected Strip +INTERVAL = 0.1 # The time (in seconds) between each increment of the binary counter +UPDATES = 60 # How many times the LEDs and effects updated per second + + +# Variables +boot = Button(plasma2040.USER_SW) + +# Pick *one* LED type by uncommenting the relevant line below: + +# APA102 / DotStar™ LEDs +# strip = plasma.APA102(NUM_LEDS, 0, 0, plasma2040.DAT, plasma2040.CLK) + +# WS2812 / NeoPixel™ LEDs +strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma2040.DAT, + color_order=plasma.COLOR_ORDER_RGB) + +# Create a new effect player to control the LED strip +player = StripPlayer(strip, num_leds=NUM_LEDS) + +# Create a BinaryCounterFX effect +binary = BinaryCounterFX(interval=INTERVAL) + +# Set up the binary counter effect to play, mirrored at the middle of the strip. +player.effects = [ + binary(i) for i in range(NUM_LEDS // 2) +] + [ + binary(NUM_LEDS // 2 - 1 - i) for i in range(NUM_LEDS // 2) +] + + +# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt) +try: + strip.start(UPDATES) # Start updating the LED strip + player.start(UPDATES) # Start the effects running, with a lower update rate than normal + + # Loop until the effect stops or the "Boot" button is pressed + while player.is_running() and not boot.raw(): + pass + +# Stop any running effects and turn off the LED strip +finally: + player.stop() + strip.clear() diff --git a/examples/plasma/examples/pulse_wave.py b/examples/plasma/examples/pulse_wave.py new file mode 100644 index 0000000..445dce8 --- /dev/null +++ b/examples/plasma/examples/pulse_wave.py @@ -0,0 +1,56 @@ +import plasma +from plasma import plasma2040 +from picofx import StripPlayer +from picofx.mono import PulseWaveFX +from pimoroni import Button + +""" +Play a wave of pulses on Plasma 2040's strip output. +This is an *experimental* feature, that can struggle when +complex effects with high update rates are applied to many LEDs. + +Press "Boot" to exit the program. +""" + +# Constants +NUM_LEDS = 60 # How many LEDs are on the connected Strip +SPEED = 0.2 # The speed to cycle the pulses at, with 1.0 being 1 second +UPDATES = 30 # How many times the LEDs and effects updated per second + + +# Variables +boot = Button(plasma2040.USER_SW) + +# Pick *one* LED type by uncommenting the relevant line below: + +# APA102 / DotStar™ LEDs +# strip = plasma.APA102(NUM_LEDS, 0, 0, plasma2040.DAT, plasma2040.CLK) + +# WS2812 / NeoPixel™ LEDs +strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma2040.DAT, + color_order=plasma.COLOR_ORDER_RGB) + +# Create a new effect player to control the LED strip +player = StripPlayer(strip, num_leds=NUM_LEDS) + +# Create a PulseWaveFX effect +wave = PulseWaveFX(speed=SPEED, length=NUM_LEDS) + +# Set up the wave effect to play, mirrored at the middle of the strip. +# Each output has a different position along the wave, with the value being related to the effect's length +player.effects = [wave(i) for i in range(NUM_LEDS)] + + +# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt) +try: + strip.start(UPDATES) # Start updating the LED strip + player.start(UPDATES) # Start the effects running, with a lower update rate than normal + + # Loop until the effect stops or the "Boot" button is pressed + while player.is_running() and not boot.raw(): + pass + +# Stop any running effects and turn off the LED strip +finally: + player.stop() + strip.clear() diff --git a/examples/plasma/examples/rainbow_wave.py b/examples/plasma/examples/rainbow_wave.py new file mode 100644 index 0000000..fdbb02b --- /dev/null +++ b/examples/plasma/examples/rainbow_wave.py @@ -0,0 +1,56 @@ +import plasma +from plasma import plasma2040 +from picofx import StripPlayer +from picofx.colour import RainbowWaveFX +from pimoroni import Button + +""" +Play a rainbow wave effect on Plasma 2040's strip output. +This is an *experimental* feature, that can struggle when +complex effects with high update rates are applied to many LEDs. + +Press "Boot" to exit the program. +""" + +# Constants +NUM_LEDS = 60 # How many LEDs are on the connected Strip +SPEED = 0.2 # The speed to cycle the rainbow at, with 1.0 being 1 second +UPDATES = 20 # How many times the LEDs and effects updated per second + + +# Variables +boot = Button(plasma2040.USER_SW) + +# Pick *one* LED type by uncommenting the relevant line below: + +# APA102 / DotStar™ LEDs +# strip = plasma.APA102(NUM_LEDS, 0, 0, plasma2040.DAT, plasma2040.CLK) + +# WS2812 / NeoPixel™ LEDs +strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma2040.DAT, + color_order=plasma.COLOR_ORDER_RGB) + +# Create a new effect player to control the LED strip +player = StripPlayer(strip, num_leds=NUM_LEDS) + +# Create a RainbowWaveFX effect +rainbow = RainbowWaveFX(speed=SPEED, length=NUM_LEDS) + +# Set up the rainbow wave effect to play. +# Each output has a different position along the wave, with the value being related to the effect's length +player.effects = [rainbow(i) for i in range(NUM_LEDS)] + + +# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt) +try: + strip.start(UPDATES) # Start updating the LED strip + player.start(UPDATES) # Start the effects running, with a lower update rate than normal + + # Loop until the effect stops or the "Boot" button is pressed + while player.is_running() and not boot.raw(): + pass + +# Stop any running effects and turn off the LED strip +finally: + player.stop() + strip.clear() diff --git a/picofx/__init__.py b/picofx/__init__.py index 8f815dc..9f11fe1 100644 --- a/picofx/__init__.py +++ b/picofx/__init__.py @@ -97,8 +97,12 @@ class EffectPlayer: DEFAULT_FPS = 100 def __init__(self, leds, num_leds=None): - self.__leds = leds if isinstance(leds, (tuple, list)) else [leds] - self.__num_leds = len(self.__leds) if num_leds is None else num_leds + if num_leds is None: + self.__leds = leds if isinstance(leds, (tuple, list)) else [leds] + self.__num_leds = len(self.__leds) + else: + self.__leds = leds + self.__num_leds = num_leds self.__effects = [None] * self.__num_leds self.__data = [()] * self.__num_leds @@ -145,7 +149,7 @@ def __update(self, timer): if self.__paired is not None: self.__paired.__update(timer) - except Exception as e: + except BaseException as e: self.stop() raise e @@ -234,8 +238,8 @@ def __show(self): class StripPlayer(EffectPlayer): - def __init__(self, rgb_leds, num_leds=60): - super().__init__(rgb_leds, num_leds) + def __init__(self, led_strip, num_leds=60): + super().__init__(led_strip, num_leds) def __show(self): for i in range(self.__num_leds):