View Source 3. Fledex: Animations
# In this example we'll use the simple setup (experiments are inteded to not run on real
# hardware but on a normal livebook, This makes it easier to stay up-to-date and experiment
# We start to define our fledex library, directly linking to the latest version on github
Mix.install([
{:fledex, "~>0.2"}
])
# we define a couple of aliases to not have to type that much
alias Fledex.LedAnimationManager
alias Fledex.Leds
alias Fledex.LedsDriver
alias Fledex.LedStripDriver.KinoDriver
alias Fledex.Color.Correction
{:ok, pid} = LedAnimationManager.start_link()
:ok
Preparation
To start with, we define a couple of aliases to make our life easier and more importantly, we start our LedAnimationManager
. We will use it to create animations. The animations are actually maintained by the LedAnimator, but we will interact with it only through the LedAnimationManager
.
Helper functions
We define a bit of helper functions that we will use when we define our animations. Those helper functions are the actual definitions of how the ledstrip will look.
Note that the functions get in a map (here called triggers) that can contain serveral triggers. It will definitely contain one trigger (caused by the LedsDriver
) with the name of the led strip. The structure does not need to be used, but can be used in order to change the animation based on the trigger. Here we use the trigger in the send configuration to specify an offset to the leds and thereby create a movement.
defmodule HelperFunctions do
@rainbow Leds.leds(50) |> Leds.func(:rainbow, num_leds: 50, reversed: true)
def rainbow(_triggers) do
@rainbow
end
def send_config(triggers) do
%{offset: triggers[:john]}
end
end
Creating a first animation
Now it's time to define our first animation by using the LedAnimationManager
. Before we can define our animations we first have to define (and configure) our led strip. The LedAnimationManager
can manage serveral strips at the same time.
We call our led strip :john
(it has to be an atom). In this example we will only use the simple kino driver (and configure it with defaults) and thereby display the result within our livebook.
LedAnimationManager.register_strip(:john, :kino)
LedAnimationManager.register_animations(:john, %{
caine: %{
def_func: &HelperFunctions.rainbow/1,
send_config_func: &HelperFunctions.send_config/1
}
})
Replacing our animation
We can now redefine our animation by regisetering different functions. Here we define a 3 led wide red dot that moves slowly from right to left.
import Bitwise
defmodule HelperFunctions2 do
@red_leds Leds.leds(50) |> Leds.light(:red) |> Leds.light(:red) |> Leds.light(:red)
def red_leds(_triggers) do
@red_leds
end
def send_config(triggers) do
slow_offset = rem(triggers[:john] >>> 5, 50)
%{offset: slow_offset}
end
end
LedAnimationManager.register_animations(:john, %{
caine: %{
def_func: &HelperFunctions2.red_leds/1,
send_config_func: &HelperFunctions2.send_config/1
}
})
Defining serveral animations
It's also possible to define serveral animations. Here we continue with our previous animation (we do have to explicitly specify it again, otherwise it would be removed) and add a new animation with 3 leds that move faster from right to left.
import Bitwise
defmodule HelperFunctions3 do
@rgb_leds Leds.leds(50) |> Leds.light(:red) |> Leds.light(:green) |> Leds.light(:blue)
def rgb_leds(_triggers) do
@rgb_leds
end
def send_config(triggers) do
faster_offset = 50 - rem(triggers[:john] >>> 2, 50)
%{offset: faster_offset}
end
end
LedAnimationManager.register_animations(:john, %{
caine: %{
def_func: &HelperFunctions2.red_leds/1,
send_config_func: &HelperFunctions2.send_config/1
},
doe: %{
def_func: &HelperFunctions3.rgb_leds/1,
send_config_func: &HelperFunctions3.send_config/1
}
})
Use of anonymous functions
It is also possible to use an anonymous function during the definition which avoids to create a separate module. Here we redefine our above definition, but this time we define :doe
with an anonymous function. To really see that we have changed the definition we define the leds as all blue. In addition we change the send_config_func
to animate the dots even faster.
The advantage of using the anonymous functions is that you don't get any compilation error, that occures if you recompile the module. Try it out by reevaluating the below definition several times and then doing the same thing with the previous definition.
This allows for a smooth replacement of definitions.
LedAnimationManager.register_animations(:john, %{
caine: %{
def_func: &HelperFunctions2.red_leds/1,
send_config_func: &HelperFunctions2.send_config/1
},
doe: %{
def_func: fn _triggers ->
Leds.leds(50) |> Leds.light(:blue) |> Leds.light(:blue) |> Leds.light(:blue)
end,
send_config_func: fn triggers ->
faster_offset = 50 - rem(triggers[:john] >>> 1, 50)
%{offset: faster_offset}
end
}
})
From now on we will only define our definitions through the use of anonymous functions.