Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

4. Fledex: Clock Example

livebooks/4_fledex_clock_example.livemd

4. Fledex: Clock Example

Mix.install([
  {:fledex, "~>0.5"}
])

# we define a couple of aliases to not have to type that much
alias Fledex.Animation.Manager
alias Fledex.Driver.Impl.Kino
alias Fledex.Leds
alias Fledex.LedStrip

{:ok, pid} = Manager.start_link()

:ok

Intro

The goal of this project is to create a clock that displays its hour, minute and second on the trip. We use the kino driver as output and we limit the amount of leds to a reasonable number. Therefore we can’t really display every second and every minute. We can get a bit creative in how we display it.

But before we get there, we first initiate our led strip.

Preparational steps

First we register a strip (we name it :clock) with our Fledex.Animation.Manager and we use the default settings for the Kino driver.

Then we modify the led strip to update with a very low frequency. Our clock only updates every second and therefore it’s unnecessary that we update it more often than that. To avoid any issues due to some runtime delays, we update it twice every second. Thereby the second indicator will never jump an led.

# we start with the default configuration but change the timer update frequency to 500ms
:ok = Manager.register_strip(:clock, [{Kino, []}], timer_update_timeout: 500)

:ok

Defining our clock

We now register our animations for the :clock led strip. We define 4 animations. One for the seconds, minutes, and hours and one as help to make it easier to read the lock by having an indicator in every 5 intervals.

Each animation consists of two elements:

  • def_func this defines a function that will be called to define a sequence of LEDs (how many LEDs and which colors). The function receives a trigger (a map) that can contain various information, but at least contains a counter with the name of the led strip (i.e. in our case with the name :counter). We will use this to define a sequence of the correct length and color the fist led. In this function we don’t use the trigger
  • send_config_func this defines a function that will be called after the LED strip has been defined (see Fledex.Leds.send/2 for more details and options). We will use this to rotatae the led sequence (dependent on the trigger that we also get here as input) in such a way that the colored dot will come to the correct position in the sequence. We also explicitly specify the direction of our rotation. We can rotate to the left or the right.

Note: we get the time by simply making a call to Time.utc_now/0 and adjusting it to our timezone (UTC+1) (Time.add/2). We then extract (through pattern matching) the information we are intersted in (second, minute, hour)

Our :help “animation” defines an led sequence of 5 leds (the first one being colored) and repeats that pattern 12 times. This is not a real animation, since we output a static pattern every time.

config = %{
  seconds: %{
    type: :animation,
    def_func: fn _triggers ->
      Leds.leds(60) |> Leds.light(:red)
    end,
    send_config_func: fn _triggers ->
      # we work with utc times and adjust, so we don't need to load a timezone library
      %{hour: _hour, minute: _minute, second: second} = Time.utc_now() |> Time.add(1, :hour)
      # Logger.info("#{second}")
      %{offset: second, rotate_left: false}
    end
  },
  minutes: %{
    type: :animation,
    def_func: fn _triggers ->
      Leds.leds(60) |> Leds.light(:green)
    end,
    send_config_func: fn _triggers ->
      # we work with utc times and adjust, so we don't need to load a timezone library
      %{hour: _hour, minute: minute, second: _second} = Time.utc_now() |> Time.add(1, :hour)
      # Logger.info("#{second}")
      %{offset: minute, rotate_left: false}
    end
  },
  hours: %{
    type: :animation,
    def_func: fn _triggers ->
      Leds.leds(60) |> Leds.light(:blue)
    end,
    send_config_func: fn _triggers ->
      # we work with utc times and adjust, so we don't need to load a timezone library
      %{hour: hour, minute: _minute, second: _second} = Time.utc_now() |> Time.add(1, :hour)
      # Logger.info("#{second}")
      %{offset: hour, rotate_left: false}
    end
  },
  help: %{
    type: :animation,
    def_func: fn _triggers ->
      Leds.leds(5)
      |> Leds.light(:ash_gray)
      |> Leds.repeat(12)
    end
  }
}

Starting our animation

Now that we have defined our configuration we can start our animation, by registering our animations-configuration to our Fledex.Animation.Manager by calling register_config/2. That’s it!

Manager.register_config(:clock, config)

If you are searching for your led strip then scoll up. It’s displayed where you have registered your led strip with the Fledex.Animation.Manager.