Fledex.Animation.Animator (fledex v0.6.0)
View SourceThe client often wants to run some animations. This can of course be done by
repeatedly updating the Leds definitions and calling
Leds.send() to send it to the driver.
This often results in constructs like the following:application
Enum.each(1..10, fn index ->
Leds
|> led_definition function(index)
|> Leds.send(config)
Process.sleep(600)
end)This creates a loop over some led definition, sends it to the LED strip and then waits for a while to do the next step. The index can be used for either influencing the led definition function, or the offset of the strip and thereby influencing the animation.
This approach is not really good, because of the following drawbacks:
- it is difficult to update the animation while it's running, because it would require to interrupt the loop
- the sending to the LED strip can not be optimized, except by knowing at which update frequency the driver is updating the strip. Of course it would be possible for a client to figure this out, but who would do that?
The idea of this module is to take care of those concerns by implementing a GenServer that runs the loop, but can be updated in-between.
From the above example it can be seen that two things can be updated:
- The led_definition_function and
- The send config (even though we will have to implement that as a function too due to the handling of the index)
Note: the time is not something that can be specified, since the animator will
be triggered by Fledex.LedStrip in it's update frequency. Thus to implement
some wait pattern, the trigger counter (or some other timer logic) should be used
Both of them can be set by defining an appropriate function and setting and resetting a reference at will
Summary
Types
The configuration of an animator.
Functions
Returns a specification to start this module under a supervisor.
(Re-)Configure this animation. You will have to implement this function on server side. This will look something like the following
Create a new animation (with a given name and configuration) for the led strip with the specified name.
When the animation is no long required, this function should be called.
Update the configuration of an effect at runtime
Types
@type config_t() :: %{ type: :animation | :static, def_func: (map() -> Fledex.Leds.t()), options: keyword() | [], effects: [{module(), keyword()}] }
The configuration of an animator.
:type: whether we have an:animationor a:staticelement. A static element can not be animated, but otherwise everything else is the same.:def_func: defines a function that returns the definition of an led sequence. It takes a map as input that can contain trigger information (like the led strip refresh counter):options: a set up options that can be specified with the animation:effects: a list of effects (seeFledex.Effect.*with their configurations. For static elements that will not have any effect, since the display will not be refreshed.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
(Re-)Configure this animation. You will have to implement this function on server side. This will look something like the following:
@spec handle_cast({:config, config_t}, state_t) :: {:noreply, state_t}
def handle_cast({:config, config}, state) do
# do something here
{:noreply, state}
end
@spec start_link(strip_name :: atom(), animation_name :: atom(), config :: config_t()) :: GenServer.on_start()
Create a new animation (with a given name and configuration) for the led strip with the specified name.
When the animation is no long required, this function should be called.
@spec update_effect(atom(), atom(), :all | pos_integer(), keyword()) :: :ok
Update the configuration of an effect at runtime
Sometimes you want to change the configuration of an effect not only at definition time, but aiso at runtime. It is possible to apply the configuration change to ALL effects of the animator, which can be convenient especially if you want to enable/disable all effects at once.