Module bluez_agent

Source
Expand description

Pairing Aranet sensors with BlueZ on Linux.

Before aranet-core connects to a sensor on Linux, it pairs the sensor if BlueZ doesn’t list it as paired. Otherwise BlueZ asks for pairing by itself on every connection: its battery plugin reads the sensor’s Battery Level, which needs encryption. That request needs an agent. With none registered, as on a headless host, BlueZ refuses it and the connection’s reads can stall until they time out; a desktop’s agent shows a pairing dialog instead. Each pairing is one short session:

  1. If the sensor refused to pair less than 10 minutes ago in this process (AuthenticationFailed or AuthenticationRejected, as when it wants a PIN), skip it and connect without pairing.
  2. On aranet-core’s own runtime, open a private connection to the system bus and read the sensor’s org.bluez.Device1.Paired property. A paired sensor ends the session.
  3. Register a NoInputNoOutput agent at /dev/rye/aranet/agent on that connection (org.bluez.AgentManager1.RegisterAgent).
  4. Call org.bluez.Device1.Pair on the same connection. It gets as long as a connect that waits for BlueZ’s service discovery would. If it runs out while BlueZ still lists the sensor as not paired, CancelPairing stops it. If BlueZ doesn’t answer whether it is paired, closing the connection stops a pairing that is still running.
  5. Unregister the agent and close the connection.

When BlueZ connects the sensor for Pair, it answers Pair only after its service discovery has finished, which can take an Aranet4 about 20 s, but it lists the sensor as paired as soon as the bond exists. A Pair that runs out of time after that counts as paired and isn’t cancelled, which would remove the new bond. The connect goes ahead, and the session keeps its connection open, with the agent unregistered, until BlueZ answers Pair: closing it earlier would cancel that discovery.

BlueZ sends the agent requests of a Pair call to the agent that the calling connection registered. On a host with no other agent, BlueZ also makes the session’s agent the default one while it is registered, so the agent approves requests only for the object path of the sensor being paired and rejects the rest. It always rejects AuthorizeService, and RequestPasskey, which would need a keyboard. Closing the connection removes the agent and cancels an unfinished pairing, even when the session is cut short.

aranet never asks to be BlueZ’s default agent, and it keeps no agent registered between connects. Since BlueZ 5.51 the first agent to register becomes the default one, so a long-lived agent on a host without a desktop agent would receive the pairing requests of every nearby device. Scans, and sensors that are already paired, never register an agent.

A pairing that fails is logged as a warning, and the connect goes ahead unpaired, with the stall or the dialog described above. The next connect pairs again, unless the sensor refused.

The session’s agent has no display or keyboard, so it can’t pair a sensor that asks for its PIN. Some such sensors don’t refuse (an Aranet2 with BlueZ 5.82, for example): the pairing finishes without the PIN, then the sensor rejects that bond at every later connect, so its reads fail while BlueZ lists it as paired, and a new bond made the same way fails the same way. Pair such a sensor once by hand, with its PIN; aranet then uses that bond. To do that, stop every aranet process that uses it (a connect during the pairing cancels it) and run bluetoothctl remove <MAC>. Then run bluetoothctl and, at its prompt, scan on until the sensor is listed, scan off and pair <MAC>, entering the PIN when asked. A one-line bluetoothctl pair <MAC> registers no agent, so on a host without a desktop agent it can’t ask for the PIN. A sensor that has lost its bond with this computer (after a reset, for example) is still listed as paired, and its encrypted reads fail too: remove the stale bond with bluetoothctl remove <MAC>. The next connect then pairs it again, unless it asks for its PIN; then pair it by hand as above.

Functions§

ensure_agentDeprecated
Does nothing.