# `Delux`
[🔗](https://github.com/elixir-circuits/delux/blob/v0.4.2/lib/delux.ex#L5)

Use LEDs for your user interface

`delux` simplifies creating and running LED blink patterns for use as part of a
user interface for an embedded hardware. This library provides:

* Low overhead LED control via Linux's Sysclass interface - blink sequences
  get compiled down so that they can be run inside the Linux kernel.
* Built-in LED effects for common use cases like blinking, cycling LED colors,
  etc.
* Prioritization of LED effects
* Support for many physical LED configurations
* Nice textual descriptions of what the LED is doing to support remote debug

This library is primarily intended for devices with 1 to 10 LEDs. It's
currently not for Neopixels and other "smart" LEDs that are more typically
found in larger numbers, but could be used for a similar purpose.

Before diving in, some terminology is needed:

* LED - one light emitting element. This doesn't have to be an LED, but the
  Linux kernel must think that it is and show a directory for it under
  `/sys/class/leds/`.
* Indicator - a group of 1, 2, or 3 LEDs that a user would perceive as one.
  This could be a lone green LED, or a red, green and blue LED in one package,
  or any combination.
* Program - a one-time or repeating set of instructions for controlling an
  indicator.
* Pattern - a low-level sequence of brightness and duration tuples for
  controlling one LED
* Slot - a holder for a program. Slots are ordered so a program put in a higher
  priority slot will take precedence over one in a lower priority slot. For
  example, if there's a UI feedback slot and a network status slot, programs
  running in the UI feedback slot could take precedence.

To give a flavor of how `delux` works, here's an example that configures
`delux` with one green LED and then blinks it at 2 Hz:

```elixir
iex> Delux.start_link(indicators: %{default: %{green: "led0"}})
iex> Delux.render(Delux.Effects.blink(:green, 2))
iex> Delux.info()
green at 2 Hz
```

This starts Delux with one indicator, `:default`, that has a green LED known to
Linux as `"led0"`. The `Delux.Effects.blink/2` function creates a 2 Hz blinking
program for Delux to render. With nothing else specified, `Delux.render/1` runs
the program on the default indicator in the default slot.

# `indicator_config`

```elixir
@type indicator_config() :: %{
  optional(:red) =&gt; String.t(),
  optional(:green) =&gt; String.t(),
  optional(:blue) =&gt; String.t()
}
```

Configuration for an indicator

Specify the Linux LED name for each LED. Single LED indicators should use a
color that's close or just choose `:red`.

# `indicator_name`

```elixir
@type indicator_name() :: atom()
```

The name for one indicator

An indicator may be composed of multiple LEDs, but they're arranged such that
it looks like one light source to someone looking at it. For example, an RGB
LED has 3 LEDs inside of it.

These can be anything you want. If you don't explicitly specify indicator
names, an indicator named `:default` is used.

# `options`

```elixir
@type options() :: [
  led_path: String.t(),
  slots: [slot()],
  indicators: %{required(indicator_name()) =&gt; indicator_config()},
  name: atom() | nil,
  backend: keyword(),
  initial:
    Delux.Program.t()
    | {Delux.Program.t(), slot()}
    | {%{required(indicator_name()) =&gt; indicator_config()}, slot()}
]
```

Delux configuration options

* `:indicators` - a map of indicator names to their configurations
* `:slots` - a list of slot atoms from lowest to highest priority. Defaults to `[:status, :notification, :user_feedback]`
* `:name` - register the Delux GenServer using this name. Defaults to `Delux`. Specify `nil` to not register a name.
* `:backend` - options for the backend
  * `:led_path` - the path to the LED directories (defaults to `"/sys/class/leds"`)
  * `:hz` - the Linux kernel's `HZ` setting. Delux will adjust its timing based on this setting (defaults to 1000)
* `:initial` - a program or a map of indicators to programs to run on initialization. If
  unset, then Delux turns off all indicators on initialization.

# `slot`

```elixir
@type slot() :: atom()
```

A name of a slot for an indicator program

Slots determine which program is rendered when more than one can be
shown at the same time. The default slot is `:status` which is also the
lowest priority slot. The `:notification` and `:user_feedback` slots are
higher priority. For example, rendering visual feedback to the user pressing a button
can be assigned to the `:user_feedback` slot so the user knows that the
button pressed worked regardless of what else is happening.

# `adjust_brightness`

```elixir
@spec adjust_brightness(GenServer.server(), 0..100) :: :ok
```

Adjust the overall brightness of all indicators

Effects are adjusted based on the value passed.

NOTE: This is not fully supported yet!

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear`

```elixir
@spec clear(GenServer.server(), slot()) :: :ok
```

Clear out all programs in the specified slot

The indicator is turned off if there are no programs in any slot.

# `info`

```elixir
@spec info() :: :ok
```

Call `info/2` with the defaults

# `info`

```elixir
@spec info(indicator_name()) :: :ok
```

Call `info/2` with the specified indicator

# `info`

```elixir
@spec info(GenServer.server(), indicator_name()) :: :ok
```

Print out info about an indicator

This is handy when you can't physically see an indicator. It's intended for
users at the IEx prompt. For programmatic use, see `info_as_ansidata/2`.

# `info_as_ansidata`

```elixir
@spec info_as_ansidata() :: IO.ANSI.ansidata()
```

Call `info_as_ansidata/2` with the defaults

# `info_as_ansidata`

```elixir
@spec info_as_ansidata(indicator_name()) :: IO.ANSI.ansidata()
```

Call `info_as_ansidata/2` with the specified indicator

# `info_as_ansidata`

```elixir
@spec info_as_ansidata(GenServer.server(), indicator_name()) :: IO.ANSI.ansidata()
```

Return user-readable information about an indicator

# `render`

```elixir
@spec render(
  %{required(indicator_name()) =&gt; Delux.Program.t() | nil}
  | Delux.Program.t()
  | nil
) :: :ok
```

Helper for rendering a program when using Delux's defaults

This calls `render/3` using the default Delux GenServer and default slot.

# `render`

```elixir
@spec render(
  %{required(indicator_name()) =&gt; Delux.Program.t() | nil}
  | Delux.Program.t()
  | nil,
  slot()
) ::
  :ok
```

Helper for rendering a program to a slot

This calls `render/3` using the default Delux GenServer.

# `render`

```elixir
@spec render(
  GenServer.server(),
  %{required(indicator_name()) =&gt; Delux.Program.t() | nil}
  | Delux.Program.t()
  | nil,
  slot()
) :: :ok
```

Update one or more indicators to a new program

Passing `nil` for the program removes the program running in the specified
slot. This is the same as calling `clear/2`.

# `start_link`

```elixir
@spec start_link(options()) :: GenServer.on_start()
```

Start an Delux GenServer

See `t:options()` for configuration options

---

*Consult [api-reference.md](api-reference.md) for complete listing*
