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 as 1/true or 0/false.
  • power: The amount of power (via PWM) being supplied to the LED, expressed as an integer between 0 (no power) and 255 (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 each PiGlow.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

@type enable() :: [boolean()] | binary()
@type power() :: [integer()] | binary()

Link to this section Functions

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

map_enable(fun, pid \\ PiGlow)

View Source
@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
Link to this function

map_enable_and_power(fun, pid \\ PiGlow)

View Source
@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
Link to this function

map_power(fun, pid \\ PiGlow)

View Source
@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
Link to this function

set_enable(values, pid \\ PiGlow)

View Source
@spec set_enable(enable(), pid()) :: :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 or false 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
Link to this function

set_enable_and_power(values, pid \\ PiGlow)

View Source
@spec set_enable_and_power([{boolean(), integer()}] | {enable(), power()}, pid()) ::
  :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 by set_enable/1.
    • power_values can be in either format (binary or list) accepted by set_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
Link to this function

set_power(values, pid \\ PiGlow)

View Source
@spec set_power(power(), pid()) :: :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) to 255 (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.

This function also accepts all the options accepted by GenServer.start_link/3.

return-values

Return values

Same as GenServer.start_link/3.

Link to this function

stop(timeout \\ 60000, pid \\ PiGlow)

View Source
@spec stop(timeout(), pid()) :: :ok

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
Link to this function

wait(timeout \\ 60000, pid \\ PiGlow)

View Source
@spec wait(timeout(), pid()) :: :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