Skip to content

bluetooth

stable

Bluetooth Low Energy toolkit providing a simulated BtDevice class for scan/connect/GATT workflows plus utilities for UUID expansion, MAC parsing, advertisement decoding, and RSSI classification.

use plugin bluetooth::{BtDevice.new, connect, disconnect, …}
19 functions Systems
/ filter jk navigate Esc clear
Functions (19)
  1. BtDevice.new Create a simulated BLE device handle
  2. connect Connect to the device
  3. disconnect Disconnect from the device
  4. is_connected Check whether the device is connected
  5. get_name Get the device name
  6. get_mac Get the device MAC address
  7. get_rssi Get the current signal strength
  8. set_rssi Set the simulated signal strength
  9. discover_services List the device's GATT services
  10. add_service Add a service UUID to the device
  11. info Get a summary table of device state
  12. scan Run a simulated BLE scan
  13. uuid128_from_short Expand a 16-bit UUID to a full 128-bit UUID
  14. parse_mac Parse a MAC address string into 6 bytes
  15. format_mac Format 6 bytes as a MAC address string
  16. parse_advertisement_data Decode BLE advertisement data structures
  17. service_name Look up a BLE service name by 16-bit UUID
  18. gatt_characteristic_name Look up a GATT characteristic name by 16-bit UUID
  19. rssi_quality Classify an RSSI value as a quality string

Overview

The bluetooth plugin is a Bluetooth Low Energy (BLE) toolkit built around a simulated BtDevice class and a set of stateless protocol utilities. The simulation lets you exercise full scan, connect, and GATT-discovery workflows without real hardware: scan returns a fixed table of sample devices, and each BtDevice is a stateful handle that tracks its connection status, RSSI, and registered services. The utility functions are pure helpers for the data formats BLE works with — 16-bit and 128-bit UUIDs, MAC addresses, advertisement payloads, and signal strength in dBm.

Reach for this plugin when prototyping BLE logic, testing signal-quality or service-discovery code paths, or decoding the raw byte structures that show up in advertisement data. Because BtDevice is a handle, you create one with BtDevice.new(name, mac) and then call methods on it; the underlying device state persists for the life of the handle.

Common patterns

Scan, connect to the strongest device, and enumerate its services:

use plugin bluetooth::{scan, rssi_quality, BtDevice, service_name}

for d in scan() {
  print("{d["name"]} {d["mac"]} ({rssi_quality(d["rssi"])})")
}

let dev = BtDevice.new("Heart Rate Monitor", "AA:BB:CC:DD:EE:01")
dev.connect()
for svc in dev.discover_services() {
  print("service {svc["uuid"]} -> {service_name(svc["uuid"])}")
}

Build a device, register an extra service, and inspect its summary:

use plugin bluetooth::{BtDevice, service_name}

let dev = BtDevice.new("Fitness Band", "AA:BB:CC:DD:EE:03")
dev.add_service(0x180F)  // Battery Service
dev.add_service(0x180D)  // Heart Rate
let i = dev.info()
print("{i["name"]}: {i["service_count"]} services, connected={i["connected"]}")

Normalize identifiers across the UUID and MAC formats:

use plugin bluetooth::{uuid128_from_short, parse_mac, format_mac}

print(uuid128_from_short("180D"))   // 0000180D-0000-1000-8000-00805F9B34FB
print(format_mac(parse_mac("aa-bb-cc-dd-ee-ff")))  // AA:BB:CC:DD:EE:FF

Create a simulated BLE device handle

Creates a simulated BLE device handle with the given name and MAC address. The device starts disconnected with a default RSSI of -50 and the Generic Access (0x1800) and Generic Attribute (0x1801) services.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Heart Rate Monitor", "AA:BB:CC:DD:EE:01")
print(dev.get_name())

Connect to the device

Connects to the device and returns true. Errors if the device is already connected.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
dev.connect()
print(dev.is_connected())  // true

Disconnect from the device

Disconnects from the device and returns true. Errors if the device is not connected.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
dev.connect()
dev.disconnect()
print(dev.is_connected())  // false

Check whether the device is connected

Returns true if the device is currently connected, false otherwise. Useful for guarding operations that require a live connection, such as discover_services.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
if !dev.is_connected() {
  dev.connect()
}
print(dev.is_connected())  // true

Get the device name

Returns the device name supplied at construction.

Get the device MAC address

Returns the device MAC address supplied at construction.

Get the current signal strength

Returns the device's current RSSI (received signal strength) in dBm.

use plugin bluetooth::{BtDevice, rssi_quality}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
let rssi = dev.get_rssi()
print("signal: {rssi} dBm ({rssi_quality(rssi)})")

Set the simulated signal strength

Sets the simulated RSSI value for the device. Useful for testing signal-quality logic.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
dev.set_rssi(-85)
print(dev.get_rssi())  // -85

List the device's GATT services

Returns a table of the device's GATT services, each entry a table with uuid (16-bit integer) and name fields. Errors if the device is not connected.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
dev.connect()
for svc in dev.discover_services() {
  print("{svc["uuid"]} -> {svc["name"]}")
}

Combine with service_name to resolve any UUID, including services added after construction:

use plugin bluetooth::{BtDevice, service_name}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
dev.connect()
dev.add_service(0x181A)  // Environmental Sensing
for svc in dev.discover_services() {
  print("{service_name(svc["uuid"])}")
}

Add a service UUID to the device

Adds a 16-bit service UUID to the device's service list, visible in subsequent discover_services calls.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
dev.add_service(0x180F)  // Battery Service

Get a summary table of device state

Returns a summary table of the device's current state: name, MAC, RSSI, connection status, and number of registered services.

use plugin bluetooth::{BtDevice}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
let i = dev.info()
print("{i["name"]} ({i["mac"]}) connected={i["connected"]}")

Run a simulated BLE scan

Runs a simulated BLE scan and returns a table of discovered devices. Each entry has name, mac, rssi, and a services table of 16-bit service UUIDs.

use plugin bluetooth::{scan, rssi_quality}

for dev in scan() {
  print("{dev["name"]} {dev["mac"]} rssi={dev["rssi"]} ({rssi_quality(dev["rssi"])})")
}

Expand a 16-bit UUID to a full 128-bit UUID

Expands a 16-bit BLE UUID given as a hex string (e.g. "180A" or "0x180A", at most 4 hex characters) into the full 128-bit UUID using the Bluetooth Base UUID 0000XXXX-0000-1000-8000-00805F9B34FB.

use plugin bluetooth::{uuid128_from_short}

let full = uuid128_from_short("180D")
print(full)  // 0000180D-0000-1000-8000-00805F9B34FB

Parse a MAC address string into 6 bytes

Parses a MAC address string in AA:BB:CC:DD:EE:FF or AA-BB-CC-DD-EE-FF form into 6 raw bytes. Errors if the string does not have exactly 6 valid hex octets.

use plugin bluetooth::{parse_mac}

let bytes = parse_mac("AA:BB:CC:DD:EE:FF")

Format 6 bytes as a MAC address string

Formats exactly 6 bytes as an uppercase colon-separated MAC address string. Errors if the input is not 6 bytes long.

use plugin bluetooth::{parse_mac, format_mac}

let bytes = parse_mac("aa-bb-cc-dd-ee-ff")
print(format_mac(bytes))  // AA:BB:CC:DD:EE:FF

Decode BLE advertisement data structures

Decodes raw BLE advertisement payload bytes into a table of AD structures. Each entry is a table with length, type (AD type byte), and data (the structure's payload bytes). Parsing stops at a zero-length entry or truncated data.

use plugin bluetooth::{parse_advertisement_data}

let entries = parse_advertisement_data(adv_bytes)
for entry in entries {
  print("type={entry["type"]} length={entry["length"]}")
}

Pair it with parse_mac to build the byte payload that an advertisement might carry:

use plugin bluetooth::{parse_mac, parse_advertisement_data}

let adv_bytes = parse_mac("02:01:06:03:03:0D")
for entry in parse_advertisement_data(adv_bytes) {
  print("AD type {entry["type"]}")
}

Look up a BLE service name by 16-bit UUID

Looks up the human-readable name of a standard BLE service by its 16-bit UUID (e.g. 0x180D"Heart Rate", 0x180F"Battery Service"). Returns "Unknown Service" for unrecognized UUIDs.

use plugin bluetooth::{service_name}

print(service_name(0x180D))  // Heart Rate
print(service_name(0x181A))  // Environmental Sensing

Look up a GATT characteristic name by 16-bit UUID

Looks up the human-readable name of a standard GATT characteristic by its 16-bit UUID (e.g. 0x2A19"Battery Level", 0x2A37"Heart Rate Measurement"). Returns "Unknown Characteristic" for unrecognized UUIDs.

use plugin bluetooth::{gatt_characteristic_name}

print(gatt_characteristic_name(0x2A19))  // Battery Level

Classify an RSSI value as a quality string

Classifies an RSSI value (dBm) into a quality string: "excellent" (≥ -30), "good" (≥ -50), "fair" (≥ -70), "weak" (≥ -90), or "unusable" (below -90).

use plugin bluetooth::{rssi_quality}

print(rssi_quality(-45))  // good
print(rssi_quality(-95))  // unusable

Drive it from a live device to label its current signal:

use plugin bluetooth::{BtDevice, rssi_quality}

let dev = BtDevice.new("Sensor", "AA:BB:CC:DD:EE:02")
dev.set_rssi(-25)
print(rssi_quality(dev.get_rssi()))  // excellent
enespt-br