2b Fledex: How to define LEDs
Mix.install(
[
{:fledex, "~>0.5"}
],
# necessary to enable the nicer rendering
consolidate_protocols: false
)
Intro
The Fledex.Leds
module allows you to easily define a sequence of LEDs. In this livebook we will look at the following aspects:
- the different color concepts
- defining individual LEDs (in sequence and out of sequence)
- merging LED sequences
- repeating an LED sequence
- defining LEDs through a function (gradient & rainbow)
-
sending leds to a
Fledex.LedStrip
Color concepts
Fledex allows to define colors in many different ways.
One very common one is to work with an integer (as defined in Types.colorint
) with a representation of the color similar to the html notation It’s best to write the color as hexadecimal, since each color has a range from 0 to 255 (i.e gets 2 digits), i.e 0xrrggbb (rr=red, gg=green, bb=blue).
Example: 0x2cafe4
where red has a value of 0x2c
(44), green of 0xaf
(175), and blue of 0xe4
(228)
.This is equivalent to the decimal 2 928 612
.
# we define our own color
my_color1 = 0x2CAFE4
my_color2 = 2_928_612
Fledex.Color.KinoRender.new([my_color1, my_color2])
Fledex does also allow to specify an {r, g, b}
triple (as defined in Types.rgb
). Each color is again in the 0 to 255 range and you can either write it as decimal or as hexadecimal number.
my_color3 = {0x2C, 0xAF, 0xE4}
my_color4 = {44, 175, 228}
Fledex.Color.KinoRender.new([my_color3, my_color4])
The next most convenient way is to defined a color through its name (see Fledex.Color.Names
).
We will look at this in more detail in a later chapter
alias Fledex.Color.Names
# note, this is a slightly different color compared to the above one, since the exact color
# does not exist. "Cerulean (Crayola): {28, 170, 214} is roughly the same color
my_color5 = :cerulean_crayola
my_color6 = Names.info(my_color5)
my_color7 = Names.cerulean_crayola()
Fledex.Color.KinoRender.new([my_color5, my_color6, my_color7])
From the color names you can also get more information, but as mentioned above we’ll look at this in a later chapter.
In addition, you might encounter, in some cases, other color encodings like Type.hsv
or Typee.hsl
. But they are in general not so important.
Defining individual Leds
In Fledex you define a sequence of LEDs (and their colors) through the Leds
module.
You first define the size of the sequence. Let us define a sequence of 30 LEDs (by calling Leds.leds
):
alias Fledex.Leds
leds = Leds.leds(30)
Each LED in that sequence does not have any color assigned to it and therefore is (by definition) switched off (black).
It is now possble to define individual LEDs in that sequence by simply specifying the color through the Leds.light()
functions and chaining them together:
leds =
leds
|> Leds.light(0xFF0000)
|> Leds.light(:green)
|> Leds.light(255)
As can be seen, every time we call the light
function we move an index
to know which one we defined as last and we can thereby simply define the light one after the next. It should be noted that the leds are one-indexed.
It is possible to define specific LEDs by specifying an offset. Let’s extend our leds:
alias Fledex.Color.Names
leds =
leds
|> Leds.light(:red, offset: 10)
|> Leds.light(Names.green())
|> Leds.light({0, 0, 0xFF})
As seen, if we specify the offset: 10
and we continue to define colors without offset the next LED in the sequence will be defined (i.e with offset 11
)
If you are curious, take a look at the Raw
tab which shows how this is encoded:
%Fledex.Leds{
...
leds: %{1 => 16711680, 2 => 65280, 3 => 255, 10 => 16711680, 11 => 65280, 12 => 255},
...
}
We have a map
(%{}
) with the offset
as key and the color as value. We also remember the position where we should insert the next light:
%Fledex.Leds{
...
meta: %{index: 13}
...
}
It is possble to define a color with an invalid offset. i.e. which is outside the allowed range. This is not a problem. The information will be carried around, but will be ignored . Take a look at the Raw
data of the next example where we define a light at offset: 40
even tough we only have 30 leds:
leds =
leds
|> Leds.light(:green, offset: 40)
It’s important to remember that the information is retained, since in some circumstances, it is possible that it might become visible again (like changing the led count through Fledex.Leds.set_count
)
Merging LED sequences
It is quite commonly that you want to define an LED sequence as a combination of serveral other sequences. This can easily be done by passing Leds
as if it were a single light:
leds_sub =
Leds.leds(2)
|> Leds.light(0xFF0000)
|> Leds.light(0x00FF00)
leds =
Leds.leds(30)
# define the red-green once
|> Leds.light(leds_sub)
# define the red-green a second time with an offset
|> Leds.light(leds_sub, offset: 5)
Repeating an LED sequence
It is possble to define a sequence of LEDs by repeating it. If you want to have 5 red LEDs you define a single LED and instruct it to be repeated 5 times. This would look like this:
leds =
Leds.leds(30)
|> Leds.light(:red, offset: 5, repeat: 5)
You can also use this to repeat a sub-sequence. This will repeat the whole subsequence as many times in a row as specified.
leds_sub =
Leds.leds(2)
|> Leds.light(0xFF0000)
|> Leds.light(0x00FF00)
leds =
Leds.leds(30)
|> Leds.light(leds_sub, offset: 5, repeat: 3)
Definining LEDs through a function
When you want to create a color sequence that is more complex, then this can also be achieved through some functions.
If, for example, you want to create a rainbow pattern over 10 LEDs, you can do so by using the rainbow/2
function.
Note: If you don’t specify the nubmer of leds, all leds in the sequence will be used (here it woudl be all 30 leds)
leds =
Leds.leds(30)
|> Leds.rainbow(num_leds: 10)
Another function is the gradient/3
function that allows a transition from one color to another.
leds =
Leds.leds(30)
|> Leds.gradient(:red, :blue)
repeat/2
is another function that will take the already defined sequence (size x
) and repeats it y
times. Hence, the newly returned led sequence size will be: size = x * y
.
Leds.leds(10)
|> Leds.gradient(:red, :blue)
|> Leds.repeat(3)
Sending LEDs to an led-strip
Once we have defined our Leds, we can send them to our Fledex.LedStrip
. This is not
difficult, but it’s such a common task that the Leds module provides the convenience
function send/2
. and some supporting functions (set_led_strip_info/3
, rotate/2
,
to_list/1
).
We won’t discuss the send function in detail, since we’ll look at this in more details in other chapters.