Bluetooth Mesh tutorial : Friend Feature Explained

Bluetooth Mesh tutorial : Friend Feature Explained
How Low Power Nodes survive in a Mesh network — Friend Request, Offer, Clear, Subscription, and Heartbeat
📡
Transport Layer
Control Messages
🔋
Low Power
Node Support
🤝
Friendship
Protocol

What is the Friend Feature?

In a Bluetooth Mesh network, most nodes are always on — they relay messages, listen continuously, and forward traffic. But some devices run on small batteries: sensors, switches, door locks. These are called Low Power Nodes (LPN).

An LPN cannot afford to stay awake all the time. So it finds a helper — a Friend node — that stays awake on its behalf. The Friend node stores messages for the LPN while it sleeps. When the LPN wakes up, it polls the Friend and collects its messages.

This relationship between an LPN and a Friend node is called a Friendship. The messages that establish, maintain, and tear down this friendship are called Transport Control messages — and that is exactly what this tutorial covers.

Keywords

Low Power Node (LPN) Friend Node Friend Request Friend Offer Friend Clear Friend Clear Confirm Friend Subscription List Heartbeat Transport Control Opcode Poll Timeout ReceiveWindow QueueSize LPNCounter TTL Master Security Credentials

1. Big Picture: How Friendship Works

Before diving into individual messages, here is how the overall friendship process flows:

Low Power Node (LPN)
Wakes up, broadcasts
Friend Request
Waits for offers,
picks best Friend
Sends Friend Poll
periodically
Manages Subscription List
(group addresses)
Goes to sleep
between polls

──── Request ────▶
◀─── Offer ─────
──── Poll ───────▶
◀─── Update/Data ─
zzz (sleep)

Friend Node
Listens for requests,
sends Friend Offer
Friendship established,
starts queuing messages
Responds to Poll with
queued messages
Manages subscriptions
on behalf of LPN
Stays awake,
stores messages

Think of the Friend node as a post office for the LPN. The LPN checks in periodically to collect its mail, then goes back to sleep.

2. Friend Offer (Opcode 0x04)

When a Friend node hears a Friend Request from an LPN, it replies with a Friend Offer message. This message tells the LPN what the Friend node can offer — how long it will keep a receive window open, how many messages it can queue, and how many subscription addresses it can track.

Field Size (bytes) What it means
ReceiveWindow 1 How long (in ms) the Friend node keeps its radio window open after an LPN poll. Range: 1–255 ms.
QueueSize 1 Number of messages the Friend can store for the LPN while it sleeps.
SubscriptionListSize 1 How many group/virtual addresses the Friend node can track for the LPN.
RSSI 1 Signal strength (dBm) measured by the Friend node when it received the Friend Request. Signed 8-bit. 0x7F means “not available”.
FriendCounter 2 Running count of how many Friend Offer messages this Friend node has ever sent (used for deduplication).

Key rules:

  • TTL must be set to 0 — this message must not be relayed.
  • Must use master security credentials.
  • LPN picks the best offer based on RSSI and capabilities.

ReceiveWindow visualised:

LPN sends Poll
← ReceiveWindow (e.g. 100ms) →
Friend responds

Within ReceiveWindow, the LPN keeps its radio on and listens for the Friend’s response.

3. Friend Clear & Friend Clear Confirm (Opcodes 0x05 / 0x06)

What happens when an LPN wants to switch to a new Friend? Or when it establishes a completely new friendship? The new Friend node sends a Friend Clear message to the old Friend node to terminate the previous friendship.

New Friend Node
Has new relationship
with LPN
──── Friend Clear ────▶
(LPNAddress + LPNCounter)
◀── Clear Confirm ─────
(echoes LPNAddress + LPNCounter)
Old Friend Node
Removes LPN from
its queue

Message Field Size Purpose
Friend Clear
(0x05)
LPNAddress 2 Unicast address of the LPN being removed from old friendship
LPNCounter 2 Counter value from the new Friend Request (proves freshness)
Friend Clear Confirm
(0x06)
LPNAddress 2 Same unicast address echoed back
LPNCounter 2 Same LPNCounter echoed back
Retry logic: Friend Clear is a confirmed message. If no reply arrives, the new Friend node retries at doubling intervals: 2s → 4s → 8s → 16s … until it receives a confirm OR the LPN’s Poll Timeout is reached.
Validity check: The old Friend node checks whether the LPNCounter in the Friend Clear is within 0–255 of the LPNCounter that established the original friendship (modulo 65536). This prevents stale or replayed clear messages.

4. Friend Subscription List (Opcodes 0x07 / 0x08 / 0x09)

An LPN can be part of groups — for example, “all lights in room 3” or “all temperature sensors on floor 2”. These are represented as group addresses and virtual addresses.

Since the LPN sleeps, the Friend node must know which group addresses to watch for and store messages from. The LPN tells the Friend node its subscriptions using three messages:

📥 Subscription List Add
Opcode: 0x07
LPN → Friend
Adds group/virtual addresses
Max 5 addresses per unsegmented message
📤 Subscription List Remove
Opcode: 0x08
LPN → Friend
Removes group/virtual addresses
Max 5 addresses per unsegmented message
✅ Subscription List Confirm
Opcode: 0x09
Friend → LPN
Acknowledges Add or Remove
Only carries TransactionNumber

Field Size Description
TransactionNumber 1 Identifies each transaction. The Confirm echoes this to match request and response.
AddressList 2 × N List of group/virtual addresses to add or remove. N = number of addresses.
Security note: These three messages use friendship security credentials (not master credentials), because they are private between the LPN and its Friend node. TTL is set to 0 — no relaying.

5. Heartbeat (Opcode 0x0A)

The Heartbeat message is sent by any mesh node to help other nodes figure out the network topology. It is not specific to the Friend feature, but it is part of the same Transport Control message layer.

By counting hops taken for a Heartbeat to arrive, a node can determine how many relay hops away the sender is. This is used to configure TTL values, identify unreachable nodes, and debug mesh connectivity.

Node A broadcasts Heartbeat (TTL=5) Relay 1 (TTL=4) Relay 2 (TTL=3) Node B receives (TTL=3, so 2 hops away)

6. Transport Control Opcode Summary
Opcode Message Direction Security
0x03 Friend Request LPN → All Friends Master
0x04 Friend Offer Friend → LPN Master
0x05 Friend Clear New Friend → Old Friend Master
0x06 Friend Clear Confirm Old Friend → New Friend Master
0x07 Subscription List Add LPN → Friend Friendship
0x08 Subscription List Remove LPN → Friend Friendship
0x09 Subscription List Confirm Friend → LPN Friendship
0x0A Heartbeat Any → Any Master

7. BlueZ / Linux — Exploring Mesh Friend Feature

BlueZ includes bluetooth-meshd, the Linux Bluetooth Mesh daemon. You can experiment with mesh nodes, including the Friend feature, using the mesh-cfgclient and meshctl tools.

Step 1 — Check if meshd is running:

sudo systemctl status bluetooth-meshd
# or start it manually:
sudo /usr/libexec/bluetooth/bluetooth-meshd --nodetach -d

Step 2 — Launch meshctl (interactive mesh shell):

meshctl

Step 3 — Create or join a mesh network:

[meshctl]# create
# This provisions the local node and creates a new network
# You will get a UUID for the node

Step 4 — Enable the Friend feature on a node via config client:

[meshctl]# menu config
[config]# target 0100
# 0100 is the unicast address of the node

# Set Friend feature ON (bit 1 of feature field)
[config]# set-friend on

Step 5 — Configure heartbeat publication (to monitor topology):

[config]# hb-pub set 0100 FFFF 0A 0A 0 0
# Arguments: dst  count  period  TTL  netkey-index  features
# FFFF = all-nodes address
# TTL 0A = 10 hops max

Step 6 — Inspect raw mesh network traffic with btmon:

sudo btmon
# Look for Network PDU events in the output
# You can filter for opcodes 0x03 through 0x09 in transport control

Step 7 — Python snippet to inspect mesh config via D-Bus:

import dbus

bus = dbus.SystemBus()
mesh_obj = bus.get_object("org.bluez.mesh", "/org/bluez/mesh")
mgr = dbus.Interface(mesh_obj, "org.freedesktop.DBus.ObjectManager")

objects = mgr.GetManagedObjects()
for path, interfaces in objects.items():
    if "org.bluez.mesh.Node1" in interfaces:
        props = interfaces["org.bluez.mesh.Node1"]
        print(f"Node: {path}")
        print(f"  Features: {props.get('Features', 'N/A')}")
        # Features includes friend, relay, proxy flags
Tip: The Features property in BlueZ mesh D-Bus API returns a dict with keys like friend, relay, proxy, lowPower — each a boolean. This maps directly to the Feature field in the mesh Heartbeat message.

Step 8 — Monitor friend establishment in meshd debug logs:

sudo /usr/libexec/bluetooth/bluetooth-meshd --nodetach -d 2>&1 | grep -i friend
# Look for lines like:
# "Friend Request received from 00AA"
# "Sending Friend Offer to 00AA"
# "Friendship established with LPN 00AA"

8. Quick Revision — Common Interview Points

Q: Why does Friend Offer include RSSI?

The LPN uses RSSI as one criterion to pick the best Friend. A closer Friend with stronger signal is preferred — fewer retransmissions, more reliable message delivery.

Q: Why is TTL=0 used for friendship messages?

Friendship is a direct, one-hop relationship. These messages should not be relayed across the network — they are private between LPN and Friend node.

Q: What security credentials does Subscription List Add use?

Friendship security credentials — not master credentials. This isolates LPN↔Friend communication from the rest of the network.

Q: What is the retry strategy for Friend Clear?

Exponential backoff: retries at 2s, 4s, 8s, 16s … until a Friend Clear Confirm is received or the LPN’s Poll Timeout expires.

Q: What is the max addresses in one Subscription List Add?

For an unsegmented control message: 5 addresses. More addresses require a segmented message.

Q: What does Heartbeat TTL tell the receiver?

The initial TTL minus received TTL = number of hops taken. Receivers use this to map mesh topology and configure their own TTL for reaching the sender.

Keep Learning Bluetooth Mesh

This post covered Transport Control messages for the Friend feature (Sections 3.6.5.4 – 3.6.5.10 of the Mesh Profile Specification).

Next up: Friend Poll, Friend Update, and the Mesh Security model

Leave a Reply

Your email address will not be published. Required fields are marked *