View Source PiGlow (pi_glow v0.1.0)
A module for changing the power and brightness of the LEDs on a PiGlow device.
Each PiGlow device contains 18 LEDs. (See PiGlow.LED
for a
list.) At any given time, each LED has two hardware properties:
enable
: Whether power is being supplied to the LED, expressed as1
/true
or0
/false
.power
: The amount of power (via PWM) being supplied to the LED, expressed as an integer between0
(no power) and255
(max power).
Note that these properties are independent of each other. An LED with
enabled
set to true
may still be turned off if power
is set to 0
.
Similarly, an LED with power
set to 255
will also still be turned off if
enable
is set to false
.
In general, the easiest way to use this library is to set all LEDs to
enable
= true
when your application starts, and then simply adjust the
power
values (using 0
to turn them off). (This is how most other PiGlow
libraries work.) However, having access to both properties allows for useful
tricks, such as using set_enable/1
to flash the lights on and off — without
changing their brightness, and while allowing some lights to remain off
(power
= 0
).
To set these properties, three levels of API are available:
- low: Calling
set_*
with binary arguments. This will send raw bytes to the device. - medium: Calling
set_*
with a list of values for each LED (in order). This will convert those values to the appropriate binaries, and send them using the "low" method above. - high: Calling
map_*
with a function that maps eachPiGlow.LED
structure to a value. This will create a list of values, which will be sent via the "medium" method above.
Thus, you can choose whichever approach works best for your application — for example, based on efficiency versus complexity.
asynchronous-api
Asynchronous API
With the exception of start_link/1
, wait/1
and stop/1
, all functions in
this module are asynchronous — they cast messages to the running PiGlow
instance without waiting for a reply, and they always return :ok
.
Aside from generally improving performance, this also allows rapidly queuing up multiple instructions, e.g. iterating through the full brigtness range (from 0 to 255 and back) to "pulse" the LEDs, allowing the PiGlow instance to run at full speed without waits.
In situations where you need to ensure that all your prior instructions have
completed execution, you can call wait/1
to send a synchronous request to
the instance. This will block until the PiGlow instance has finished
processing its current message queue.
process-lifecycle
Process lifecycle
You generally won't need to start a PiGlow instance manually, as starting
the application will (by default) automatically start a named instance,
unless you set config :pi_glow, start: false
in your application config.
If you do choose to manually launch a PiGlow instance, all functions in
this module (besides start_link
) accept an optional pid
argument that can
be used to specify either the PID or registered name of your launched
instance.
Note that launching or shutting down a PiGlow instance does not change the
state of the LEDs. (This is in contrast with other PiGlow libraries, which
generally apply power to all LEDs on startup, and may also remove power on
exit.) Unless you know the LEDs are already enabled for some other reason,
you'll want to use one of the *_enable
functions before any *_power
changes will be visible.
If you are using this library in a script (rather than a daemon), note also
that when a script finishes and exits, all in-flight messages are
discarded. If your script makes changes to the LEDs and then immediately
exits, there's a good chance that most or all of your changes will never get
processed. If you want to run LED events just before exiting — for example,
to turn them off — be sure to use wait/1
or stop/1
before exiting.
Link to this section Summary
Functions
Returns a specification to start this module under a supervisor.
Run a function to determine which LEDs should have power enabled or disabled.
Run a function to determine the enable status and power to send to each LED.
Run a function to determine how much power to send to each LED.
Enables or disables power to each LED.
Enables or disables power to all LEDs, and sets the amount of power, in a single operation.
Sets the amount of power being delivered to each LED.
Starts a process that will update the PiGlow device LEDs when it receives messages.
Stops a running instance and releases the I2C device.
Waits for all prior messages to be received and processed.
Link to this section Types
Link to this section Functions
Returns a specification to start this module under a supervisor.
See Supervisor
.
@spec map_enable((PiGlow.LED.t() -> boolean()), pid()) :: :ok
Run a function to determine which LEDs should have power enabled or disabled.
The fun
argument must be a function that takes one argument (a PiGlow.LED
structure) and returns a boolean. The resulting list of booleans will then
be sent to set_enable/1
. See that function for more info.
Returns :ok
immediately.
examples
Examples
# Turn on the green and blue LEDs, turn off the rest:
iex> PiGlow.map_enable(fn led -> led.colour in [:green, :blue] end)
:ok
# Turn on five LEDs at random:
iex> leds = PiGlow.LED.leds() |> Enum.take_random(5)
iex> PiGlow.map_enable(&(&1 in leds))
:ok
@spec map_enable_and_power((PiGlow.LED.t() -> {boolean(), integer()}), pid()) :: :ok
Run a function to determine the enable status and power to send to each LED.
The fun
argument must be a function that takes one argument (a PiGlow.LED
structure) and returns a 2-element tuple {enable, power}
, where enable
is
a boolean and power
is an integer in the range of 0..255
.
The resulting list of boolean-integer pairs will be unzipped and sent to
set_enable_and_power/1
. See that function for more info.
Returns :ok
immediately.
examples
Examples
# Enable red LEDs at max brightness, amber at min brightness, disable the rest.
iex> PiGlow.map_enable_and_power(fn
...> %{colour: :red} -> {true, 255}
...> %{colour: :amber} -> {true, 1}
...> _ -> {false, 0}
...> end)
:ok
@spec map_power((PiGlow.LED.t() -> integer()), pid()) :: :ok
Run a function to determine how much power to send to each LED.
The fun
argument must be a function that takes one argument (a PiGlow.LED
structure) and returns an integer in the range of 0..255
. The resulting
list of integers will then be sent to set_power/1
. See that function for
more info.
Returns :ok
immediately.
examples
Examples
# Set all LEDs to random brightness:
iex> PiGlow.map_power(fn _ -> Enum.random(1..255) end)
:ok
# Set the first arm to max brightness, the second to medium, the third to minimum.
iex> PiGlow.map_power(fn
...> %{arm: 1} -> 255
...> %{arm: 2} -> 125
...> %{arm: 3} -> 1
...> end)
:ok
Enables or disables power to each LED.
The values
argument can be specified one of two ways:
As a list of 18 booleans, with
true
orfalse
indicating whether each LED should be enabled or disabled.As a 3-byte binary, where each byte is a 6-bit integer indicating which LEDs should be enabled.
Note that LEDs require both enabled = true
and power > 0
to light up.
Use set_power/1
to adjust LED power, or set_enabled_and_power/1
to set
both in a single operation.
Always returns :ok
immediately (even if there is no PiGlow
process
running). Use wait/1
if you need to ensure your changes have been sent to
the device.
examples
Examples
# Enable LEDs at indices 1, 2, 3, 5, 8, 13:
iex> 1..18 |> Enum.map(&(&1 in [1, 2, 3, 5, 8, 13])) |> PiGlow.set_enable()
:ok
# Equivalent to:
iex> PiGlow.set_enable(<<0b111010, 0b010000, 0b100000>>)
:ok
Enables or disables power to all LEDs, and sets the amount of power, in a single operation.
The values
argument can be specified one of two ways:
As a list of 18 two-element tuples, each in the format
{enable, power}
, where enable is a boolean and power is an integer.As a two-element tuple, in the format
{enable_values, power_values}
.enable_values
can be in either format (binary or list) accepted byset_enable/1
.power_values
can be in either format (binary or list) accepted byset_power/1
.
When using this function, both instructions are sent to the I2C controller, one immediately after the other, with no "update" operation sent inbetween. This should avoid any unexpected LED flickering caused by setting each value independently.
Always returns :ok
immediately (even if there is no PiGlow
process
running). Use wait/1
if you need to ensure your changes have been sent to
the device.
examples
Examples
# Set all LEDs to minimum brightness:
iex> 1..18 |> Enum.map(fn _ -> 1 end) |> PiGlow.set_power()
:ok
# Equivalent to:
iex> PiGlow.set_power(<<1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1>>)
:ok
Sets the amount of power being delivered to each LED.
The values
argument can be specified one of two ways:
As a list of 18 integers, ranging from
0
(off) to255
(full power).As an 18-byte binary, where each byte is an integer, as above.
Note that LEDs require both enabled = true
and power > 0
to light up.
Use set_enable/1
to turn LEDs on, or set_enabled_and_power/1
to set both
in a single operation.
Always returns :ok
immediately (even if there is no PiGlow
process
running). Use wait/1
if you need to ensure your changes have been sent to
the device.
examples
Examples
# Set all LEDs to minimum brightness:
iex> 1..18 |> Enum.map(fn _ -> 1 end) |> PiGlow.set_power()
:ok
# Equivalent to:
iex> PiGlow.set_power(<<1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1>>)
:ok
@spec start_link(GenServer.options()) :: GenServer.on_start()
Starts a process that will update the PiGlow device LEDs when it receives messages.
options
Options
:bus
- I2C bus device number (default:1
):name
- Registered process name to use (default:PiGlow
)- Use value
nil
to prevent registration.
- Use value
This function also accepts all the options accepted by GenServer.start_link/3
.
return-values
Return values
Same as GenServer.start_link/3
.
Stops a running instance and releases the I2C device.
Returns :ok
once all pending messages are processed and the instance has
been cleanly stopped.
Note that PiGlow
uses a default restart policy of :transient
, meaning
that it will not be automatically restarted if stopped via this function.
If no message is received within timeout
milliseconds (default: 60
seconds), the caller will exit.
examples
Examples
# Turn off all LEDs, then shut it down:
iex> PiGlow.map_enable_and_power(fn _ -> {false, 0} end)
:ok
iex> PiGlow.stop()
:ok
Waits for all prior messages to be received and processed.
Returns :ok
once all pending messages are processed. (Note that this does
not guarantee that the PiGlow is idle, only that messages sent prior to the
start of this wait
call have been processed.)
If no message is received within timeout
milliseconds (default: 60
seconds), the caller will exit, as per standard GenServer.call/2
semantics.
examples
Examples
# Pulse all lights once:
iex> [0..255, 255..0] |>
...> Enum.flat_map(&Enum.to_list/1) |>
...> Enum.map(&PiGlow.LED.gamma_correct/1) |>
...> Enum.each(fn value ->
...> PiGlow.map_power(fn _ -> value end)
...> end)
:ok
# Wait for those 512 events to all be processed:
iex> PiGlow.wait()
:ok