Packages
Elixir library providing Bluetooth Low Energy (BLE) client functionality through a Rustler NIF. Uses the btleplug crate to scan for, connect to, and interact with BLE peripherals. POC basic functionality and only client (central) mode is supported resp. usable currently.
Current section
Files
Jump to
Current section
Files
lib/native.ex
defmodule RustlerBtleplug.Native do
@moduledoc false
version = Mix.Project.config()[:version]
use RustlerPrecompiled,
otp_app: :rustler_btleplug,
crate: :btleplug_client,
base_url: "https://github.com/adiibanez/rustler_btleplug/releases/download/v#{version}",
force_build: System.get_env("RUSTLER_BTLEPLUG_BUILD") in ["1", "true"],
version: version,
max_retries: 0,
targets: [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
"aarch64-apple-ios-sim",
"aarch64-apple-ios",
"x86_64-apple-ios",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-musl"
]
## ✅ Type Definitions
@type central() :: reference()
@type peripheral() :: reference()
@type gatt_peripheral() :: reference()
@type uuid() :: String.t()
@type mac() :: String.t()
@type state_graph() :: String.t()
# @type state_map() :: %{
# adapter: %RustlerBtleplug.AdapterInfo{},
# peripherals: %{uuid() => %RustlerBtleplug.PeripheralInfo{}},
# services: %{uuid() => %RustlerBtleplug.ServiceInfo{}},
# characteristics: %{uuid() => %RustlerBtleplug.CharacteristicInfo{}}
# }
@default_timeout 2000
## ✅ Core BLE Functions
@spec init(map()) :: {:ok, central()} | {:error, term()}
def init(_opts \\ %{}), do: error()
@spec create_central(Pid.t()) :: {:ok, central()} | {:error, term()}
def create_central(_pid \\ self()), do: error()
@spec start_scan(central(), number()) :: {:ok, central()} | {:error, term()}
def start_scan(_central, _ms \\ 1000), do: error()
@spec stop_scan(central()) :: {:ok, central()} | {:error, term()}
def stop_scan(_central), do: error()
## ✅ Peripheral Discovery
@doc """
Find a peripheral by UUID.
"""
@spec find_peripheral(central(), uuid(), number()) ::
{:ok, peripheral()} | {:error, term()}
def find_peripheral(_central, _uuid, _timeout \\ @default_timeout), do: error()
@doc """
Find a peripheral by name.
"""
@spec find_peripheral_by_name(central(), String.t(), number()) ::
{:ok, peripheral()} | {:error, term()}
def find_peripheral_by_name(_central, _name, _timeout \\ @default_timeout), do: error()
## ✅ Peripheral Connection
@spec connect(peripheral(), number()) :: {:ok, peripheral()} | {:error, term()}
def connect(_peripheral, _timeout \\ @default_timeout), do: error()
@spec disconnect(peripheral(), number()) :: {:ok, peripheral()} | {:error, term()}
def disconnect(_peripheral, _timeout \\ @default_timeout), do: error()
## ✅ Notifications & Subscriptions
@spec subscribe(peripheral(), uuid(), number()) :: {:ok, peripheral()} | {:error, term()}
def subscribe(_peripheral, _characteristic, _timeout \\ @default_timeout), do: error()
@spec unsubscribe(peripheral(), uuid(), number()) :: {:ok, peripheral()} | {:error, term()}
def unsubscribe(_peripheral, _characteristic, _timeout \\ @default_timeout), do: error()
## ✅ Adapter State Queries (Graph & Mindmap)
@doc """
Retrieve the adapter state as a **GraphViz** or **Mermaid mindmap**.
"""
@spec get_adapter_state_graph(central(), String.t()) :: {:ok, state_graph()} | {:error, term()}
def get_adapter_state_graph(_central, _variant \\ "mindmap"), do: error()
## ✅ Adapter State as Structured Map (Elixir-friendly)
@doc """
Retrieve the **full adapter state** as a structured map.
This map contains:
- `adapter` (Info about the adapter)
- `peripherals` (Map of discovered peripherals)
- `services` (Map of services)
- `characteristics` (Map of characteristics)
"""
@spec get_adapter_state_map(central()) ::
{:ok, %{
adapter: RustlerBtleplug.AdapterInfo.t(),
peripherals: %{String.t() => RustlerBtleplug.PeripheralInfo.t()},
services: %{String.t() => RustlerBtleplug.ServiceInfo.t()},
characteristics: %{String.t() => RustlerBtleplug.CharacteristicInfo.t()}
}} | {:error, term()}
def get_adapter_state_map(_central), do: error()
## ✅ Utility / Debug Functions
@spec test_string(String.t()) :: {:ok, String.t()} | {:error, term()}
def test_string(_string), do: error()
@spec add(number(), number()) :: {:ok, number()} | {:error, term()}
def add(_a, _b), do: error()
@spec get_map() :: {:ok, map()} | {:error, term()}
def get_map(), do: error()
## ❌ Handle NIF errors when Rust module isn't loaded
defp error, do: :erlang.nif_error(:nif_not_loaded)
end