Flix behaviour (Flix v0.1.0) View Source

Flix is an Elixir client for the Flic smart button.

Flic buttons don't connect directly to Flix nor the other way around. Flic buttons connect to a flicd via bluetooth. Flix applications also connect to flicd but via a TCP. See the diagram below.

+------------+  command(s)  +---------+               +---------------+
|            +------------->|         |               |               |
|  Flix App  |     TCP      |  flicd  |<--------------+  Flic Button  |
|            |<-------------+         |   Bluetooth   |               |
+------------+   event(s)   +---------+               +---------------+

You can find more information about Flic's flicd in its official page.

Writing a Flix application is as simple as defining a new Elixir module, using Flix's __using__ macro (ie. use Flix) and implementing Flix's handle_event/2 callback function.

defmodule MyFlixApp do
  use Flix

  def handle_event(event, state) do
    new_state = do_something(event, state)
    {:ok, new_state}
  end
end

Below is a full example of a Flix application where a counter is initialised to 0 and increased or decreased by one when someone does single- or double-clicks a Flic button, respectively. The code makes the following assumptions:

  • flicd is running and reachable on raspberrypi.local:5551.
  • The Flic button (ie. "80:E4:DA:78:45:1B") has already been paired with flicd.
defmodule Flix.Examples.Counter do
  use Flix

  alias Flix.Protocol.Events.ButtonSingleOrDoubleClickOrHold
  alias Flix.Protocol.Enums.ClickType

  def start(host \\ 'raspberrypi.local', port \\ 5551) do
    {:ok, client} = Flix.start(__MODULE__, 0, host, port)
    :ok = set_up(client)
    {:ok, client}
  end

  def start_link(host \\ 'raspberrypi.local', port \\ 5551) do
    {:ok, client} = Flix.start_link(__MODULE__, 0, host, port)
    :ok = set_up(client)
    {:ok, client}
  end

  def set_up(client) do
    :ok = Flix.create_connection_channel(client, "80:E4:DA:78:45:1B", 1)
  end

  def stop(client) do
    :ok = Flix.stop(client)
  end

  def handle_event(
    %ButtonSingleOrDoubleClickOrHold{click_type: ClickType.SingleClick},
    count
  ) do
    new_count = count + 1
    IO.puts "Count = #{new_count}"
    {:ok, new_count}
  end
  def handle_event(
    %ButtonSingleOrDoubleClickOrHold{click_type: ClickType.DoubleClick},
    count
  ) do
    new_count = count - 1
    IO.puts "Count = #{new_count}"
    {:ok, new_count}
  end
  def handle_event(event, count) do
    require Logger
    Logger.debug("No handle_event/2 clause in #{__MODULE__} for #{inspect(event)}")
    {:ok, count}
  end
end

Link to this section Summary

Functions

Cancels a scan wizard that was previously started.

Changes the accepted latency for this connection channel and the auto disconnect time.

Creates a battery status listener for a Flic button.

Creates a connection channel for a Flic button with the given bluetooth address. You assign a unique conn_id for this connection channel that will later be used in commands and events to refer to this connection channel.

Starts a scan wizard with the provided scan_wizard_id.

Creates a scanner with the given scan_id.

Deletes a Flic button.

Removes all connection channels among all clients for the specified Flic button.

Gets information about a Flic button. The button must have been previously paired with the server (ie.flicd).

Retrieves the current state of the server (ie. flicd process the client is connected to).

Pings the server (ie. flicd).

Removes the battery status listener identified by the provided listener_id.

Removes a previously created connection channel.

Removes the scanner with the given scan_id.

Starts a new Flix client linked to the current process.

Link to this section Callbacks

Link to this callback

handle_event(event, state)

View Source

Specs

handle_event(event :: term(), state :: term()) :: {:ok, term()}

Link to this section Functions

Link to this function

cancel_scan_wizard(client, scan_wizard_id)

View Source

Cancels a scan wizard that was previously started.

If there exists a scan wizard with the provided scan_wizard_id, it is cancelled and flicd sends a Flix.Protocol.Events.ScanWizardCompleted event to the client with the reason set to Flix.Protocol.Enums.ScanWizardResult.CancelledByUser.

Link to this function

change_mode_parameters(client, conn_id, latency_mode \\ Flix.Protocol.Enums.LatencyMode.default(), auto_disconnect_time \\ 0)

View Source

Changes the accepted latency for this connection channel and the auto disconnect time.

The latency mode is applied immediately but the auto disconnect time is applied the next time the Flic button gets connected.

Link to this function

create_battery_status_listener(client, listener_id, bt_addr)

View Source

Creates a battery status listener for a Flic button.

If the providede listener_id already exists for this client, the execution of this function has no effect.

After the execution of this function, flicd sends a Flix.Protocol.Events.BatteryStatus event to the client for the specified button. Further Flix.Protocol.Events.BatteryStatus events are sent to the client every time the battery status of the button changes. This does not usually happen more often than every three hours.

Link to this function

create_connection_channel(client, bt_addr, conn_id, latency_mode \\ Flix.Protocol.Enums.LatencyMode.default(), auto_disconnect_time \\ 0)

View Source

Creates a connection channel for a Flic button with the given bluetooth address. You assign a unique conn_id for this connection channel that will later be used in commands and events to refer to this connection channel.

After executing this function, flicd sends a Flix.Protocol.Events.CreateConnectionChannelResponse event to the client.

When a connection channel is created, the client starts listening for button events originating from the provided Flic button. There are four types of button events (ie. Flix.Protocol.Events.ButtonUpOrDown, Flix.Protocol.Events.ButtonClickOrHold, Flix.Protocol.Events.ButtonSingleOrDoubleClick, Flix.Protocol.Events.ButtonSingleOrDoubleClickOrHold). These events are annotated with the provided conn_id.

To stop receiving button events use remove_connection_channel/2.

If there already exists a connection channel with the provided conn_id, the execution of this function has no effect.

Link to this function

create_scan_wizard(client, scan_wizard_id)

View Source

Starts a scan wizard with the provided scan_wizard_id.

If there already exists a scan wizard with the same scan_wizard_id, the execution of this funcion has no effect.

Link to this function

create_scanner(client, scan_id)

View Source

Creates a scanner with the given scan_id.

After executing this function, flicd sends a Flix.Protocol.Events.AdvertisementPacket event for each advertisement packet received from a Flic button by the server (ie. flicd). Flix.Protocol.Event.AdvertisementPacket events are annotated with the provided scan_id.

To stop receiving advertisement events use remove_scanner/2.

If there already exists an active scanner with the provided scan_id, the execution of this function has no effect.

Link to this function

delete_button(client, bt_addr)

View Source

Deletes a Flic button.

If the button exists in the list of verified buttons, all connection channels will be removed for all clients for this button. Then, flicd sends the Flix.Protocol.Events.ButtonDeleted event to all clients.

If the Flic button does not exist in the list of verified buttons, the execution of this function has no effect but a Flix.Protocol.Events.ButtonDeleted is anyways sent to the client.

Link to this function

force_disconnect(client, bt_addr)

View Source

Removes all connection channels among all clients for the specified Flic button.

Link to this function

get_button_info(client, bt_addr)

View Source

Gets information about a Flic button. The button must have been previously paired with the server (ie.flicd).

After executing thisfunction, flicd sends a Flic.Protocol.Event.GetButtonInfoResponse to the client.

Retrieves the current state of the server (ie. flicd process the client is connected to).

After executing this function, flicd sends a Flix.Protocol.Events.GetInfoResponse event to the client.

Pings the server (ie. flicd).

After executing this function, flicd sends a Flix.Protocol.Event.PingResponse event to the client.

Link to this function

remove_battery_status_listener(client, listener_id)

View Source

Removes the battery status listener identified by the provided listener_id.

Link to this function

remove_connection_channel(client, conn_id)

View Source

Removes a previously created connection channel.

After executing this function, no further button events will be sent for this channel. If there are no other connection channels active to this Flic button (from neither the provided client nor other clieents), the physical bluetooth connection between flicd and the Flic button is disconnected.

Link to this function

remove_scanner(client, scan_id)

View Source

Removes the scanner with the given scan_id.

The client will stop receiving Flix.Protocol.Event.AdvertisementPacket events.

Link to this function

start(module, state, host \\ 'localhost', port \\ 5551)

View Source

Starts a new Flix client without links.

See start_link/4 for more details.

Link to this function

start_link(module, state, host \\ 'localhost', port \\ 5551)

View Source

Starts a new Flix client linked to the current process.

This is often used to start the Flix as part of a supervision tree.

A Flix client is nothing but a GenServer sprinkled with some custom logic. See GenServer.start_link/3 for more details.