Adding a 5 second pause to Tiny FX code

Hello - I’m working on a project to build a lighthouse style lighting effect using the TinyFX and the ‘pulse wave’ example - so far I’ve built a little 3d printed lantern for the leds:

lighthouse

but i’m stuck on the code (complete python novice). My desired effect is to cycle the LEDs once (like a lighthouse sweep) and then wait for 5 seconds (similar to the lighthouse flash pattern at Orfordness, which the model is based on), then repeat.

With the example code I’ve tried starting the stopping the player at the bottom:

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():
time. sleep(0.7) 
player.stop()
tiny.shutdown()
time. sleep(4) 
player.start() 
    pass

Stop any running effects and turn off all the outputs

finally:
player.stop()
tiny.shutdown()

but it starts where the code stopped running, so is incomplete cycle. Working out the exact timings is complicated. Is there a simpler way or am I missing something?

It might be that you have to call player.stop(reset_fx = True). But I am not sure what kind of side-effects this has. Just try it.

(when you post code, include everything in triple backticks: ``` abc ```).

Could you please share the model of your lantern?

You could modify the PulseWaveFX class that’s being used by adding an additional, optional constructor argument named “delay”. If not included it would be ignored (i.e., the current behaviour). The source code is found in: tinyfx/lib/picofx/mono/pulse.py

You do need to import the utime library. I haven’t tested this but it would be something like:

import utime
import math 
from picofx import Cycling

class PulseFX(Cycling):
    def __init__(self, speed=1, phase=0):
        super().__init__(speed)
        self.phase = phase

    def __call__(self):
        angle = (self.__offset + self.phase) * math.pi * 2
        return (math.sin(angle) + 1) / 2.0

class PulseWaveFX(Cycling):
    def __init__(self, speed=1, length=1, phase=0.0, delay=0):
        super().__init__(speed)
        self.length = length
        self.phase = phase
        self.delay = delay

    def __call__(self, pos):
        def fx():
            nonlocal pos
            phase = pos / self.length
            angle = (self.__offset + self.phase + phase) * math.pi * 2
            return (math.sin(angle) + 1) / 2.0
        if self.delay > 0:
            utime.sleep(self.delay)
        return self, fx

To use this, you’d add a delay argument to your last effect:

wave(5, delay=5)

This would wait 5 seconds inside the __call__() method before returning a value.

here you go: Printables

Thanks, great! I’ll give it a try.

I think what @bablokb suggests would be the best approach rather than modifying the PulseWaveFX (at this stage anyway).

I do similar in this example: picofx/examples/tiny_fx/examples/showcase/space_tales_with_pir.py at main · pimoroni/picofx · GitHub
where I have the lights play an effect for a few seconds after triggered my a motion sensor. It shouldn’t be too difficult to modify this for your 5 second delay.

A custom FX could be written to handle it too, but this would need to be a class based off Updatable rather than Cycling to give it access to the internal timing values, like the TrafficFX does: picofx/picofx/mono/traffic.py at main · pimoroni/picofx · GitHub

If anyone has a go at this, I’d happily accept any pull request :)