On_cycle_complete question

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
Draculen
 
Posts: 72
Joined: Mon Jan 24, 2022 11:14 pm

On_cycle_complete question

Post by Draculen »

Looking through the adafruit animation library code I see that for animation groups/sequence there is a on_cycle_complete call and receive definition, but I couldn't find any tutorial info on how this is used.


Can this be used in place of advance_interval? For instance Instead of a neopixel animation playing repeatedly for x amount of seconds could on_cycle_complete just play the animation through once and when it's done move on to the next animation sequence?

I'm trying to animate multiple neopixel animations with durations to cycle all the way through the animation if that helps any

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: On_cycle_complete question

Post by mikeysklar »

There are some docs for using on_cycle_complete(). Make sure the animations you use support it and that you are enabling it with cycle_complete set to True.

https://docs.circuitpython.org/projects ... t/api.html
on_cycle_complete()
Called by some animations when they complete an animation cycle. Animations that support cycle complete notifications will have X property set to False. Override as needed.
class adafruit_led_animation.sequence.AnimateOnce(*members, **kwargs)
Wrapper around AnimationSequence that returns False to animate() until a sequence has completed. Takes the same arguments as AnimationSequence, but overrides advance_on_cycle_complete=True and advance_interval=0
advance_on_cycle_complete (bool) – Automatically advance when on_cycle_complete is triggered on member animations. All Animations must support on_cycle_complete to use this.

User avatar
Draculen
 
Posts: 72
Joined: Mon Jan 24, 2022 11:14 pm

Re: On_cycle_complete question

Post by Draculen »

So for multiple animation sequences encased within an animation group. Each animation would have to have this bool set to true?

Or is it a direct replacement for advance_interval? Meaning within the over arching animation group you would set on_cycle_complete to true and also cycle count needs to be set to 1?
I'm just confused on where it should be declared I guess

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: On_cycle_complete question

Post by mikeysklar »

Since not all the animations support on_cycle_complete() the first thing you want to do is review the animations you are using and check their python code to see if they support it.

Set up a simple test code.py that uses an on_cycle_complete() compatible animation like sequence.py (nothing complicated like a group of animations) and enable the property with:

Code: Select all

advance_on_cycle_complete=True


https://github.com/adafruit/Adafruit_Ci ... nce.py#L84

User avatar
Draculen
 
Posts: 72
Joined: Mon Jan 24, 2022 11:14 pm

Re: On_cycle_complete question

Post by Draculen »

Thank you for the reply. I will be testing this as soon as I get home.

I'm using comet which does support cycle complete however the other animation sequence is sparkle with a comet running through the sparkles. The sparkle animation does not support cycle complete, would it be as simple as changing the source code to include a definition for on_cycle_complete? Or because the actual animation. Doesn't have a start and end point like the comet animation is it not that simple?

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: On_cycle_complete question

Post by mikeysklar »

You could make a copy of the original comet and sparkle PY files and work on adding the code from sequence.py for on_cycle_complete() support.

This is the core of it, but there will be other variables needed for the code to run.

Code: Select all

     def on_cycle_complete(self):
        """
        Called by some animations when they complete an animation cycle.
        Animations that support cycle complete notifications will have X property set to False.
        Override as needed.
        """
        self.cycle_count += 1
        if self.cycle_count % self.notify_cycles == 0:
            for callback in self._also_notify:
                callback(self)
https://github.com/adafruit/Adafruit_Ci ... ce.py#L120

User avatar
Draculen
 
Posts: 72
Joined: Mon Jan 24, 2022 11:14 pm

Re: On_cycle_complete question

Post by Draculen »

I'm running into some syntax issues trying to implement on_cycle_complete into sparkle

In the comet animation (because it already supports on_cycle_complete) it has
this block of code which nice and cleanly calls reset() along with an else
statement to flag cycle_complete as true.

for the sparkle animation, the only place I seem to be able to call
cycle_complete would be in def after_draw(self) at the very bottom of the code/script

however placing def on_cycle_complete anywhere in the sparkle code meets me with
an unknown syntax error. on_cycle_complete_supported is flagged as true. I figured
this bool would be inherited by the parent Animation script

am I missing something obvious?

Code: Select all

# Write your code here :-)
# SPDX-FileCopyrightText: 2020 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
`adafruit_led_animation.animation.sparkle`
================================================================================

Sparkle animation for CircuitPython helper library for LED animations.

* Author(s): Kattni Rembor

Implementation Notes
--------------------

**Hardware:**

* `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_
* `Adafruit DotStars <https://www.adafruit.com/category/885>`_

**Software and Dependencies:**

* Adafruit CircuitPython firmware for the supported boards:
  https://circuitpython.org/downloads

"""

import random
from adafruit_led_animation.animation import Animation
from adafruit_led_animation.sequence import AnimationSequence # added by draculen
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LED_Animation.git"


class Sparkle(Animation):
    """
    Sparkle animation of a single color.

    :param pixel_object: The initialised LED object.
    :param float speed: Animation speed in seconds, e.g. ``0.1``.
    :param color: Animation color in ``(r, g, b)`` tuple, or ``0x000000`` hex format.
    :param num_sparkles: Number of sparkles to generate per animation cycle.
    :param mask: array to limit sparkles within range of the mask
    """

    # pylint: disable=too-many-arguments
    def __init__(
        self, pixel_object, speed, color, num_sparkles=1, name=None, mask=None
    ):
        if len(pixel_object) < 2:
            raise ValueError("Sparkle needs at least 2 pixels")
        if mask:
            self._mask = mask
        else:
            self._mask = []
        if len(self._mask) >= len(pixel_object):
            raise ValueError("Sparkle mask should be smaller than number pixel array")
        self._half_color = color
        self._dim_color = color
        self._sparkle_color = color
        self._num_sparkles = num_sparkles
        self._num_pixels = len(pixel_object)
        self._pixels = []
        super().__init__(pixel_object, speed, color, name=name)
        

    def _set_color(self, color):
        half_color = tuple(color[rgb] // 4 for rgb in range(len(color)))
        dim_color = tuple(color[rgb] // 10 for rgb in range(len(color)))
        for pixel in range(  # pylint: disable=consider-using-enumerate
            len(self.pixel_object)
        ):
            if self.pixel_object[pixel] == self._half_color:
                self.pixel_object[pixel] = half_color
            elif self.pixel_object[pixel] == self._dim_color:
                self.pixel_object[pixel] = dim_color
        self._half_color = half_color
        self._dim_color = dim_color
        self._sparkle_color = color



                
    def _random_in_mask(self):
        if len(self._mask) == 0:
            return random.randint(0, (len(self.pixel_object) - 1))
        return self._mask[random.randint(0, (len(self._mask) - 1))]

on_cycle_complete_supported = True # input by Draculen

    def draw(self):
        self._pixels = [self._random_in_mask() for _ in range(self._num_sparkles)]
        for pixel in self._pixels:
            self.pixel_object[pixel] = self._sparkle_color

    def after_draw(self):
        self.show()
        for pixel in self._pixels:
            self.pixel_object[pixel % self._num_pixels] = self._half_color
            if (pixel + 1) % self._num_pixels in self._mask:
                self.pixel_object[(pixel + 1) % self._num_pixels] = self._dim_color
                


    def on_cycle_complete(self): # added by Draculen
       
        self.cycle_count += 1
        if self.cycle_count % self.notify_cycles == 0:
            for callback in self._also_notify:
                callback(self)

User avatar
Draculen
 
Posts: 72
Joined: Mon Jan 24, 2022 11:14 pm

Re: On_cycle_complete question

Post by Draculen »

Would it be more practical to just make a personally tailored "fake" on_cycle_complete? I'm not sure if you can call something equivalent to a coroutine in the sparkle animations class since I don't think it has an update loop but if easier: I would just make the animation count to 8 seconds and then flag on_cycle_complete as true(if even possible) I've been just beating my head on my keyboard all weekend trying to find the magic variables to make this work and it seems like it's just not possible

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”