8. Fledex: Component
Mix.install([
{:fledex, "~>0.4"}
])
Setup
use Fledex
The Weather animation (with a component)
Instead of defining the complicated logic of the termometer indicator, we use this time a component that has all this logic build in. The component defines our configuration and all we have to do is to specify the mandatory (and if desired optional) parameters.
alias Fledex.Component.Thermometer
led_strip :john, :kino do
component(:thermo, Thermometer,
range: -20..40,
trigger: :temperature,
negative: :blue,
null: :may_green,
positive: :red,
marker: :davy_s_grey
)
end
Fledex.Utils.PubSub.broadcast(:fledex, "trigger", {:trigger, %{temperature: 17.2}})
To test our animation we fake again the temperature by simply publishing the desired temperature.
What is a component
The question now is just “what is a component”?
The component is simply a module that implements the @behaviour Fledex.Component.Interface
. Only a single configure/2
function is required that returns a Fledex.Animation.Manager.config_t
structure and thus can define anything you normaly would define through the animation
, static
, … macros.
To get the correct behaviour the component gets 2 parameters:
-
The name of the component: Each animation gets it’s own name, so does the component. It should be noted that an component can create several animations and the component should make sure to name each of those individually. The termometer has two “animations” the scale and the markers on the scale. The former gets the name of the component and the latter gets the name with
.helper
attached. -
a keyword list of options: The list of parameters allows us to configure our component. Each component can define their own set of components. Probably a reoccuring parameter is
:trigger_name
wich allows us to configure runtime parameters, but this is by convention only.
As you have seen a component is nothing special but it allows to redefine a reusable structure. A component can be defined and distributed through an external library.
Netsted components
We now take a slightly different approach for creating our component. As we have seen above a component is simply a configuration and the dsl is simply an easier way to write a config. Thus, we can reuse one within the other.
alias Fledex.Component.Dot
led_strip :nested_components, :kino do
component(:minute, Dot, color: :red, count: 60, trigger_name: :minute)
component(:hour, Dot, color: :blue, count: 24, trigger_name: :hour)
static :helper do
leds(5) |> light(:davy_s_grey, 5) |> repeat(12)
end
end
Fledex.Utils.PubSub.simple_broadcast(%{hour: 17, minute: 34})
The interesting thing in the Fledex.Component.Dot
component is that it actually defines the component by using the Fledex.animation/3
macro. The code looks like the following
def configure(name, options) when is_atom(name) and is_list(options) do
use Fledex
# ... here comes some option extraction stuff
animation name do
triggers when is_map(triggers) and is_map_key(triggers, trigger_name) ->
leds(count) |> light(color, triggers[trigger_name])
_ -> leds()
end
end
The clock component
The Fledex.Component.Clock
component is an interesting one, because it defines several animations and even a static pattern. For that it uses the special led_strip
driver :config
that simply returns the config instead of delegating to the Fledex.Animation.Manager
.
Each animation requires its own unique name and this is accomplished with a small utility function that combines the strip name (the one we get in) and an additional fraction.
def configure(name, options) do
# ... here comes some option extraction stuff
use Fledex
led_strip name, :config do
component :minute, Dot, color: minute_color, count: 60, trigger_name: create_name(trigger_name, :minute)
component :hour, Dot, color: hour_color, count: 24, trigger_name: create_name(trigger_name, :hour)
static create_name(trigger_name, :helper) do
leds(5) |> light(helper_color, 5) |> repeat(12)
end
end
end
As you can see it defines, more or less, the same animations as our example above. Thus, instead of us defining the different animations, the component is doing this for us. To use the component, we now simply have to use the clock and pass in the necessary options, and that’s it!
alias Fledex.Component.Clock
import Crontab.CronExpression
led_strip :nested_components2, :kino do
component({:clock_hour, :clock_minute}, Clock, trigger_name: :clock)
job :clock, ~e[* * * * * * *]e do
date_time = DateTime.utc_now()
IO.puts("ok, checking... #{date_time}")
Fledex.Utils.PubSub.simple_broadcast(%{
clock_hour: date_time.hour,
clock_minute: date_time.minute
})
end
end
And to see the correct time, we only need to publish the appropriate time. When we do so we shouldn’t forget that the animations are reacting to two triggers that we passed in. We need to publish the triggers :clock_hour
and :clock_minute
as triggers.
Fledex.Utils.PubSub.simple_broadcast(%{clock_hour: 17, clock_minute: 34})