Skip to content

Commit

Permalink
Added flashing examples
Browse files Browse the repository at this point in the history
  • Loading branch information
ZodiusInfuser committed Jul 30, 2024
1 parent 09865dd commit ef6c106
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 57 deletions.
2 changes: 1 addition & 1 deletion examples/tiny_fx/examples/effects/blink_wave.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
duty=0.5) # How long the blink is on for (from 0.0 to 1.0)


# Set up the wave effect to play. Each output has a different popsition
# Set up the wave effect to play. Each output has a different position
# along the wave, with the value being related to the effect's size
player.effects = [
wave(0),
Expand Down
48 changes: 48 additions & 0 deletions examples/tiny_fx/examples/effects/flashing_sequence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from tiny_fx import TinyFX
from picofx import MonoPlayer
from picofx.mono import FlashSequenceFX

"""
Play a flashing sequence across TinyFX's outputs.
Press "Boot" to exit the program.
"""

# Variables
tiny = TinyFX() # Create a new TinyFX object to interact with the board
player = MonoPlayer(tiny.outputs) # Create a new effect player to control TinyFX's mono outputs


# Create a FlashSequenceFX effect
flashing = FlashSequenceFX(speed=1.0, # The speed to flash at, with 1.0 being 1 second
size=6.0, # The size the effect spans, in this case the number of outputs (6)
flashes=2, # The number of flashes to do within that time
window=0.2, # How much of the flash time to perform the flashes in
phase=0.0, # How far through the flash cycle to start the effect (from 0.0 to 1.0)
duty=0.5) # How long as a percent from 0.0 to 1.0 each flash is on for


# Set up the wave effect to play. Each output has a different position
# along the wave, with the value being related to the effect's size
player.effects = [
flashing(0),
flashing(1),
flashing(2),
flashing(3),
flashing(4),
flashing(5)
]


# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
player.start() # Start the effects running

# Loop until the effect stops or the "Boot" button is pressed
while player.is_running() and not tiny.boot_pressed():
pass

# Stop any running effects and turn off all the outputs
finally:
player.stop()
tiny.clear()
2 changes: 1 addition & 1 deletion examples/tiny_fx/examples/effects/pulse_wave.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
phase=0.0) # How far through the blink to start the effect (from 0.0 to 1.0)


# Set up the wave effect to play. Each output has a different popsition
# Set up the wave effect to play. Each output has a different position
# along the wave, with the value being related to the effect's size
player.effects = [
wave(0),
Expand Down
44 changes: 44 additions & 0 deletions examples/tiny_fx/examples/effects/single_flashing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from tiny_fx import TinyFX
from picofx import MonoPlayer
from picofx.mono import FlashFX

"""
Play a flashing effect on one of TinyFX's outputs.
Press "Boot" to exit the program.
"""

# Variables
tiny = TinyFX() # Create a new TinyFX object to interact with the board
player = MonoPlayer(tiny.outputs) # Create a new effect player to control TinyFX's mono outputs


# Create and set up a blink effect to play
player.effects = [
FlashFX(speed=1.0, # The speed to flash at, with 1.0 being 1 second
flashes=2, # The number of flashes to do within that time
window=0.2, # How much of the flash time to perform the flashes in
phase=0.0, # How far through the flash cycle to start the effect (from 0.0 to 1.0)
duty=0.5), # How long as a percent from 0.0 to 1.0 each flash is on for

# No effects played on the rest of the outputs (unnecessary to list, but show for clarity)
None,
None,
None,
None,
None,
]


# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
player.start() # Start the effects running

# Loop until the effect stops or the "Boot" button is pressed
while player.is_running() and not tiny.boot_pressed():
pass

# Stop any running effects and turn off all the outputs
finally:
player.stop()
tiny.clear()
49 changes: 49 additions & 0 deletions examples/tiny_fx/examples/showcase/emergency_vehicle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from tiny_fx import TinyFX
from picofx import MonoPlayer
from picofx.mono import FlashSequenceFX, StaticFX

"""
Play an alternating flashing sequence on two of TinyFX's outputs,
recreating the effect of emergency vehicle beacons.
The other outputs are static for illuminated head and tail lights.
Press "Boot" to exit the program.
"""

# Variables
tiny = TinyFX() # Create a new TinyFX object to interact with the board
player = MonoPlayer(tiny.outputs) # Create a new effect player to control TinyFX's mono outputs


# Create a FlashSequenceFX effect
flashing = FlashSequenceFX(speed=1.0, # The speed to flash at, with 1.0 being 1 second
size=2.0, # The size the effect spans, in this case the number of outputs (6)
flashes=4, # The number of flashes to do within that time
window=0.5) # How much of the flash time to perform the flashes in

headlights = StaticFX(brightness=0.7)
taillights = StaticFX(brightness=0.5)

# Set up the mono effects to play. The first two are flashing, the rest are static
player.effects = [
flashing(0),
flashing(1),
headlights,
headlights,
taillights,
taillights
]


# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
player.start() # Start the effects running

# Loop until the effect stops or the "Boot" button is pressed
while player.is_running() and not tiny.boot_pressed():
pass

# Stop any running effects and turn off all the outputs
finally:
player.stop()
tiny.clear()
6 changes: 3 additions & 3 deletions picofx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ def pair(self, player):
self.__paired = player

def __update(self, timer):
for ufx in self.__updateables:
ufx.tick(self.__period)

try:
for ufx in self.__updateables:
ufx.tick(self.__period)

self.__show()

if self.__paired is not None:
Expand Down
5 changes: 3 additions & 2 deletions picofx/mono/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from .binary import BinaryCounterFX
from .blink import BlinkFX, BlinkWaveFX
from .emergency import EmergencyFX
from .flash import FlashFX, FlashSequenceFX
from .flicker import FlickerFX
from .pelican import PelicanLightFX
from .pulse import PulseFX, PulseWaveFX
Expand All @@ -16,7 +16,8 @@
BinaryCounterFX,
BlinkFX,
BlinkWaveFX,
EmergencyFX,
FlashFX,
FlashSequenceFX,
FlickerFX,
PelicanLightFX,
PulseFX,
Expand Down
50 changes: 0 additions & 50 deletions picofx/mono/emergency.py

This file was deleted.

64 changes: 64 additions & 0 deletions picofx/mono/flash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# SPDX-FileCopyrightText: 2024 Christopher Parrott for Pimoroni Ltd
#
# SPDX-License-Identifier: MIT

from picofx import Cycling


class FlashFX(Cycling):
def __init__(self, speed=1, flashes=2, window=0.5, phase=0.0, duty=0.5):
super().__init__(speed)
self.flashes = flashes
self.window = window
self.phase = phase
self.duty = duty

@property
def flashes(self):
return self.__flashes

@flashes.setter
def flashes(self, flashes):
if not isinstance(flashes, int) or flashes <= 0:
raise ValueError("flashes must be an integer greater than zero")

self.__flashes = int(flashes)

def __call__(self):
offset = (self.__offset + self.phase) % 1.0
if offset < self.window:
percent = ((offset * self.__flashes) / self.window) % 1.0
return 1.0 if percent < self.duty else 0.0
return 0.0


class FlashSequenceFX(Cycling):
def __init__(self, speed=1, size=1, flashes=1, window=1, phase=0.0, duty=0.5):
super().__init__(speed)
self.size = size
self.flashes = flashes
self.window = window
self.phase = phase
self.duty = duty

@property
def flashes(self):
return self.__flashes

@flashes.setter
def flashes(self, flashes):
if not isinstance(flashes, int) or flashes <= 0:
raise ValueError("flashes must be an integer greater than zero")

self.__flashes = int(flashes)

def __call__(self, pos):
def fx():
nonlocal pos
phase = pos / self.size
offset = (self.__offset + self.phase + phase) % 1.0
if offset < self.window:
percent = ((offset * self.__flashes) / self.window) % 1.0
return 1.0 if percent < self.duty else 0.0
return 0.0
return self, fx

0 comments on commit ef6c106

Please sign in to comment.