Skip to content

Commit 030077d

Browse files
author
Frank Hunleth
committed
Support starting Delux as an OTP application
This can be very convenient and allow Delux to start earlier in the boot process. The readme has been updated to talk about the main tradeoffs and hopefully nudge people to adding it to their supervision trees. This isn't always easy to do, though.
1 parent f06357c commit 030077d

5 files changed

Lines changed: 100 additions & 17 deletions

File tree

README.md

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,14 @@ Once you feel good about the indicators and slots, it's time to configure
114114

115115
## Configuration
116116

117-
After adding `delux` to your mix dependencies, add `Delux` to a supervision
118-
tree of your choice. The childspec looks like:
117+
After adding `delux` to your mix dependencies, you can either add `Delux` to a
118+
supervision tree of your choice or add a `:delux` configuration to your
119+
application environment (`config.exs`). The tradeoff is that having `Delux`
120+
start itself by specifying an application config can be really convenient, but
121+
adding `Delux` to your supervision tree allows runtime configuration and more
122+
control over failure recovery.
123+
124+
Starting with the supervision tree approach, here's an example childspec:
119125

120126
```elixir
121127
{Delux,
@@ -126,22 +132,30 @@ tree of your choice. The childspec looks like:
126132
}}
127133
```
128134

129-
The above configuration shows two indicators. The first is called `:default`
130-
and is an RGB indicator. The second is a lone red LED that's used as
131-
`:indicator2`. As mentioned before, if you only have one indicator, call it
132-
`:default`.
135+
The above configuration shows two indicators. The first is called `:default` and
136+
is an RGB indicator. The second is a lone red LED that's used as `:indicator2`.
137+
As mentioned before, if you only have one indicator, call it `:default`.
138+
139+
Other options include setting the list of slots and giving the `Delux` GenServer
140+
a name. If you don't give the `Delux` GenServer a name, it will register itself
141+
as a singleton and you won't have to pass the server name or pid to any of the
142+
API calls.
143+
144+
If you'd like Delux to start itself automatically, add the configuration to your
145+
`config.exs` or a file that it includes. Here's an example:
133146

134-
Other options include setting the list of slots and giving the `Delux`
135-
GenServer a name. If you don't give the `Delux` GenServer a name, it will
136-
register itself as a singleton and you won't have to pass the server name or
137-
pid to any of the API calls.
147+
```elixir
148+
config :delux,
149+
indicators: %{
150+
default: %{red: "led0:red", green: "led0:green", blue: "led0:blue"},
151+
indicator2: %{red: "led1"}
152+
}}
153+
```
138154

139155
## Use
140156

141-
For sake of example, lets start the `Delux` GenServer the manual way by calling
142-
`start_link/1` directly. The usual way in your programs would be to add the
143-
childspec to the supervision tree as shown earlier. Modify the LED names to
144-
whatever you have.
157+
For sake of example, let's start the `Delux` GenServer the manual way by calling
158+
`start_link/1` directly. Modify the LED names to whatever you have.
145159

146160
```elixir
147161
iex> Delux.start_link(indicators: %{
@@ -150,8 +164,8 @@ iex> Delux.start_link(indicators: %{
150164
})
151165
```
152166

153-
After you have a `Delux` GenServer and running, call `Delux.render/1` to turn
154-
on the default indicator in the default slot:
167+
After you have a `Delux` GenServer and running, call `Delux.render/1` to turn on
168+
the default indicator in the default slot:
155169

156170
```elixir
157171
iex> Delux.render(Delux.Effects.on(:white))

lib/delux/application.ex

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
defmodule Delux.Application do
2+
@moduledoc false
3+
4+
use Application
5+
6+
@impl Application
7+
def start(_type, _args) do
8+
# Optionally start Delux if configured in the application
9+
# environment
10+
11+
children =
12+
case Application.get_all_env(:delux) do
13+
[] -> []
14+
config -> [{Delux, config}]
15+
end
16+
17+
opts = [strategy: :one_for_one, name: Delux.Supervisor]
18+
Supervisor.start_link(children, opts)
19+
end
20+
end

mix.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ defmodule Delux.MixProject do
3131

3232
def application do
3333
[
34-
extra_applications: [:logger]
34+
extra_applications: [:logger],
35+
mod: {Delux.Application, []}
3536
]
3637
end
3738

test/delux_app_test.exs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
defmodule DeluxAppTest do
2+
use ExUnit.Case, async: false
3+
4+
alias Delux.Support.FakeLEDs
5+
6+
test "empty config doesn't start Delux" do
7+
assert Process.whereis(Delux) == nil
8+
end
9+
10+
@tag :tmp_dir
11+
test "single LED configuration", %{tmp_dir: led_dir} do
12+
FakeLEDs.create_leds(led_dir, 1)
13+
14+
:ok = Application.stop(:delux)
15+
Application.put_env(:delux, :backend, led_path: led_dir, hz: 0)
16+
Application.put_env(:delux, :indicators, %{default: %{green: "led0"}})
17+
:ok = Application.start(:delux)
18+
19+
on_exit(fn ->
20+
Application.stop(:delux)
21+
:application.unset_env(:delux, :backend)
22+
:application.unset_env(:delux, :indicators)
23+
:ok = Application.start(:delux)
24+
end)
25+
26+
assert info_as_binary(:default) == "off"
27+
28+
# Check initialized to off
29+
assert FakeLEDs.read_trigger(0) == "pattern"
30+
assert FakeLEDs.read_pattern(0) == "0 3600000 0 0 "
31+
32+
# Blink it
33+
Delux.render(Delux.Effects.blink(:green, 2), :status)
34+
assert info_as_binary() == "green at 2 Hz"
35+
assert FakeLEDs.read_pattern(0) == "1 250 1 0 0 250 0 0 "
36+
37+
# Clear it
38+
Delux.clear()
39+
assert info_as_binary() == "off"
40+
assert FakeLEDs.read_pattern(0) == "0 3600000 0 0 "
41+
end
42+
43+
defp info_as_binary(indicator \\ :default) do
44+
Delux.info_as_ansidata(indicator) |> IO.ANSI.format(false) |> IO.chardata_to_string()
45+
end
46+
end

test/test_helper.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
Logger.configure(level: :warning)
2+
13
ExUnit.start()

0 commit comments

Comments
 (0)