Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

bluetooth

BlueZ: adapter power, discovery, connected, paired and discovered devices, and pairing prompts.

list {
    source = mantle.bluetooth:map(function(bluetooth)
        return bluetooth and bluetooth.connected_devices or {}
    end),
    key = function(device) return device.mac end,
    itemfn = function(device)
        local battery = device.battery >= 0 and string.format(" %d%%", device.battery) or ""
        return button {
            on_click = function() mantle.bluetooth:disconnect(device.mac) end,
            children = { text { content = device.name .. battery } },
        }
    end,
}

State

mantle.bluetooth:get() returns BluetoothState, nil before the first push. A field marked ? may be absent.

FieldTypeDescription
availablebooleanBlueZ has an adapter; false without one or without bluetoothd.
connected_devicesConnectedDevice[]Paired, connected devices. Unordered and may reshuffle on any push: sort before drawing.
discoverablebooleanOther devices can find this adapter. BlueZ turns it off after DiscoverableTimeout (180 s by default).
discovered_devicesDiscoveredDevice[]Unpaired devices BlueZ knows, unordered. Kept after stop_discovery; BlueZ expires unseen temporary ones after TemporaryTimeout (30 s by default).
discoveringbooleanThe adapter is scanning, whichever client started it.
enabledbooleanThe adapter is powered.
paired_devicesPairedDevice[]Paired devices that are not connected. Unordered like connected_devices.
pairing_request?PairingRequestThe pairing question to show, or nil. Answer with answer_pairing.

ConnectedDevice

FieldTypeDescription
batteryintegerBattery percentage, or -1 when the device reports none.
busy?DeviceActionSame as DiscoveredDevice::busy.
categorystringFrom the class of device: "keyboard", "mouse", "headphones", "headset", "phone", "computer" or "generic".
macstringMAC address, e.g. "00:1A:7D:DA:71:11"; every bluetooth action takes it.
namestringThe device’s advertised name, or empty.

DeviceAction

What the shell is doing to a device, as its busy.

One of "pairing", "connecting", "disconnecting".

DiscoveredDevice

FieldTypeDescription
blockedbooleanBlueZ refuses to pair with or connect to the device until it is unblocked.
busy?DeviceActionThe action this shell is running on the device, or nil; another client’s never shows.
macstringMAC address, the argument of pair.
namestringAdvertised name, often empty when the device broadcasts only an address.
pairedbooleanAlways false.

PairedDevice

FieldTypeDescription
blockedbooleanBlueZ refuses every connection to or from the device until it is unblocked.
busy?DeviceActionSame as DiscoveredDevice::busy.
categorystringSame set as ConnectedDevice.category.
macstringMAC address, the argument of connect and forget.
namestringThe device’s advertised name, or empty.

PairingKind

What a pairing_request asks; see PairingRequest.kind.

One of "confirm", "authorize", "service", "display".

PairingRequest

What the pairing agent is asking the user.

FieldTypeDescription
code?stringSix-digit passkey for "confirm", passkey or PIN for "display", else nil.
kindPairingKind"confirm": does the device show code? "authorize": may it pair? "service": may a paired, untrusted device connect? "display": type code on the device; nothing to answer.
macstringThe device’s MAC address.
namestringThe device’s advertised name, or empty.

Actions

Call each as mantle.bluetooth:<action>(arguments...); ? marks an argument you may omit.

ActionArgumentsDescription
set_enabledenabled: booleanPowers the adapter on or off.
set_discoverablediscoverable: booleanMakes the adapter findable by other devices, or not.
start_discoveryClears discovered_devices and scans. The request holds, so a scan starts once the adapter powers on and pauses while a pair runs.
stop_discoveryStops discovery; discovered_devices stays.
pairmac: stringPairs a discovered device, then trusts and connects it.
connectmac: stringTrusts and connects a paired device.
disconnectmac: stringDisconnects a connected device.
forgetmac: stringRemoves a device from BlueZ, unpairing it.
answer_pairingmac: string, accept: booleanAccepts or rejects the pairing_request for mac; a yes within 750 ms of it appearing is ignored.

Backend

BlueZ on the system bus.

ContractBehavior
Stateorg.bluez’s ObjectManager plus property changes. An adapter added later is picked up; a bluetoothd started after the Supervisor is not. Without BlueZ, available is false, the lists stay empty and every action does nothing
AgentMantle registers the default DisplayYesNo agent at /org/mantle/Bluez/Agent1. A confirmation, authorization or displayed code becomes pairing_request only while the adapter is discoverable or Mantle is pairing that device. A "service" request asks only for a paired device. One request shows at a time: a second is rejected, unless the first only displays a code and the second needs an answer. PIN and passkey entry are rejected
Discoverystart_discovery clears discovered_devices; stop_discovery keeps it
Battery, categoryBattery1 gives battery; the Class major and minor bits give category
CodecsPipeWire owns them: audio.bluetooth lists each device’s profiles and set_bluetooth_profile switches one

Gotchas

TrapFix
A device pairing from its own side gets rejectedMantle only prompts for invited devices. Set set_discoverable to true while pairing
A device that needs a PIN typed on the computer fails to pairThe agent rejects PIN and passkey entry. Pair it with bluetoothctl, which brings its own agent

Source: supervisor/src/capabilities/bluetooth/