GATT-Based Profiles — IAS, FMP, LLS, TPS, PXP, Battery, Device Info
Chapter 15 · Part 1 of 2 · Sections 15.1–15.9 · Profile Architecture · Immediate Alert · Find Me · Link Loss · Tx Power · Proximity · Battery · Device Information
15.1 — Introduction
Why BLE Profiles Are Simpler Than Classic Bluetooth
LE profiles are dramatically simpler than their BR/EDR equivalents. The reason is the GATT-based profile concept: all the common machinery — discovering services, reading and writing characteristics, enabling notifications — is handled once inside the ATT protocol and GATT profile. Profiles on top only need to define what data to expose. They do not need to reinvent discovery, access, or notification mechanisms.
The simplicity shows in the specification documents themselves. Some GATT-based profile specs are only 10 pages. Several sit around 20 pages. Compare that to the HFP or A2DP specifications for BR/EDR which run to hundreds of pages and encode full protocol stacks of their own.
15.2 — Profile, Services, and Characteristics
The Three-Level Data Model
The GATT-based profile architecture separates profiles and services into independent specifications. A profile defines how a complete feature works — for example, proximity monitoring. A service defines one aspect of a feature — for example, transmit power. Multiple profiles can share the same service: the Device Information Service is used by at least ten different profiles.
- A device may support one or more profiles
- A profile may contain zero or more services (some profile roles have no services)
- Each service contains one or more characteristics
- Characteristics hold data values that can be read, written, indicated, or notified
- LE profiles are data-centric — each exposes specific sensor or device data
This contrasts with BR/EDR profiles like HFP or A2DP which are not data-centric — they establish audio streams rather than exposing addressable data values.
A write-only service that triggers an immediate action on the device when the remote side writes to it. Pressing a button on a phone can cause a misplaced key fob to start buzzing. The service is intentionally minimal — the only intelligence is what the device chooses to do when the alert level changes.
0x00 No Alert, 0x01 Mild Alert, 0x02 High Alert.Writing Mild or High Alert keeps the device alerting until: an implementation-specific timeout fires, the user presses a button to stop it, a new alert level is written, or the physical link disconnects.
/* Write High Alert to IAS (handle from service discovery): */
gatttool -b AA:BB:CC:DD:EE:FF \
--char-write --handle=0x0025 --value=02
/* 02 = High Alert | 01 = Mild Alert | 00 = No Alert */
/* --char-write uses Write Command (opcode 0x52, no ACK) */
/* Stop alerting: */
gatttool -b AA:BB:CC:DD:EE:FF \
--char-write --handle=0x0025 --value=00
Allows a user to locate a misplaced device by pressing a button that causes the missing device to sound an alert. A typical use case is finding a key fob using a mobile phone.
The device where the user presses the button. Writes the Alert Level into the Find Me Target’s IAS. Usually a mobile phone.
The device that raises the alert. Exposes the Immediate Alert Service. Usually a key fob or wearable that buzzes or flashes.
Neither role is required to be GAP Central or Peripheral — either device can initiate the connection. The Locator uses GATT service discovery to find the IAS on the Target before writing the alert level.
Triggers an alert when the Bluetooth connection to a remote device is unexpectedly lost — moved out of range, device stolen, or walked away. Unlike IAS, the Alert Level here is configured before the connection is lost and activated by the disconnect event itself, not by a write from the remote side.
Real-world examples: a watch that alerts when the paired phone is left behind; a child-tracker wristband that alerts a parent when the child wanders out of range.
0x00 No Alert, 0x01 Mild Alert on link loss, 0x02 High Alert on link loss.Once the connection is lost, the device alerts at the configured level until: a timeout fires, the user acknowledges it, or the physical link is reconnected.
/* Pre-configure High Alert on link loss: */
gatttool -b AA:BB:CC:DD:EE:FF \
--char-write-req --handle=0x0082 --value=02
/* Uses Write Request (opcode 0x12) — acknowledged */
/* handle 0x0082 is the LLS Alert Level characteristic value */
/* Verify configuration was stored: */
gatttool -b AA:BB:CC:DD:EE:FF \
--char-read --handle=0x0082
/* Response: 02 → High Alert configured */
Exposes the device’s current transmit power level in dBm while the connection is active. The Client uses this to estimate path loss by comparing the TPS reading with the received signal strength at its own antenna. A larger path loss means greater physical distance between the devices.
Use cases: auto-locking a computer when the user’s watch moves beyond a threshold distance; proximity-based access control in offices; distance-aware alerts in a shopping mall child-tracking system.
/* Read Tx Power Level from TPS: */
gatttool -b AA:BB:CC:DD:EE:FF \
--char-read --handle=0x0088
/* Response: fc → 0xFC signed = -4 dBm */
/* Path loss calculation: */
/* path_loss = Tx_Power_Level (from TPS) - RSSI (measured) */
/* Higher path_loss = greater distance */
/* e.g.: Tx = -4 dBm, RSSI = -65 dBm → path_loss = 61 dBm */
Monitors proximity between two devices and alerts when they move too far apart. Supports two alert triggers: a link-drop alert (when the connection drops because the devices are out of range) and a path-loss alert (when the calculated path loss exceeds a threshold, even before the connection drops).
Reads Tx Power from TPS to calculate path loss. Sets Alert Level in both LLS and IAS. Usually a phone or dual-mode device — acts as GAP Central.
Exposes LLS (mandatory), IAS (optional), and TPS (optional). Usually an LE-only device — acts as GAP Peripheral (key fob, tag, wristband).
/* Read Tx Power, compute path loss, set alert if threshold: */
/* 1. Read Tx Power Level from TPS: */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --handle=0x0088
/* 2. Read current RSSI of the connection: */
sudo hcitool rssi AA:BB:CC:DD:EE:FF
/* 3. path_loss = tx_power - rssi */
/* 4. If path_loss > threshold, write IAS Alert Level: */
gatttool -b AA:BB:CC:DD:EE:FF \
--char-write --handle=0x0085 --value=02
Provides the battery charge level as a percentage to remote devices. The client can either poll the value periodically or configure a notification to receive updates only when the level changes. Notification-based monitoring is much more efficient — the server only sends data when the battery level actually drops.
/* Read battery level: */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --uuid=0x2A19
/* Response: 4b → 0x4B = 75 (percent) */
/* Enable notification when battery level changes: */
/* Find CCCD handle (descriptor 0x2902) after 0x2A19: */
gatttool -b AA:BB:CC:DD:EE:FF --char-write-req \
--handle=0x --value=0100
/* Server will now push updates when level drops */
Provides manufacturer and device identification information. At least one characteristic must be supported — implementations choose which are relevant to their product.
/* Read all DIS characteristics: */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --uuid=0x2A29
/* Response: "Acme Corp" (Manufacturer Name) */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --uuid=0x2A24
/* Response: "HR-3000" (Model Number) */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --uuid=0x2A26
/* Response: "1.2.0" (Firmware Revision) */
/* In bluetoothctl after connect: */
[AA:BB:CC:DD:EE:FF]# menu gatt
[AA:BB:CC:DD:EE:FF]# list-attributes
/* Device Information (0x180a) */
/* Manufacturer Name String (0x2a29) */
/* Model Number String (0x2a24) */
/* ... */
