La capa Generic Attribute Profile (GATT) define cómo los dispositivos Bluetooth Low Energy exponen datos a los clientes. Para ingenieros que integran módulos Bluetooth en productos, la arquitectura de servicios GATT determina directamente el rendimiento, consumo energético e interoperabilidad de la aplicación. Este artículo cubre decisiones prácticas de diseño GATT para productos basados en módulos.
Jerarquía GATT
GATT organiza los datos en una jerarquía de cuatro niveles:
| Nivel | Descripción | Ejemplo |
|---|---|---|
| Profile | Colección de servicios para un caso de uso | Heart Rate Profile |
| Service | Grupo de characteristics relacionadas | Heart Rate Service (0x180D) |
| Characteristic | Valor nombrado con propiedades | Heart Rate Measurement (0x2A37) |
| Descriptor | Metadatos sobre una characteristic | Client Characteristic Configuration (0x2902) |
Un módulo típicamente implementa uno o más servicios primarios. Los servicios secundarios solo son significativos cuando otro servicio los referencia — en la práctica, la mayoría de los diseños de módulos los evitan.
Diseño de Servicios
Registro de Servicio Primario
Cada servicio se identifica con un UUID de 128 bits. Existen dos estrategias de asignación:
- UUIDs de 16 bits (0x1800–0x26FF): Asignados por Bluetooth SIG para servicios estandarizados. Usar cuando el módulo implementa un perfil estándar (ej.: Battery Service 0x180F).
- UUIDs custom de 128 bits: Para servicios propietarios. Generar un UUID base e incrementar los bytes inferiores para cada servicio y characteristic.
Patrón común de UUID base:
Base: 6E40XXXX-B5A3-F393-E0A9-E50E24DCCA9E Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E Char 1: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E Char 2: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
Este enfoque, usado por el servicio UART de Nordic, simplifica la gestión de UUIDs en una línea de productos.
Propiedades de Characteristic
Cada characteristic declara propiedades que controlan cómo los clientes interactúan con ella:
| Propiedad | Opcode | Dirección | Caso de uso |
|---|---|---|---|
| Read | 0x0A | Client → Server | Valores de configuración |
| Write | 0x12 | Client → Server | Comandos de control |
| Write Without Response | 0x52 | Client → Server | Comandos de alta frecuencia |
| Notify | — | Server → Client | Streaming de datos sensores |
| Indicate | — | Server → Client | Alertas críticas |
| Broadcast | — | Server → All | Advertising tipo beacon |
Notification vs Indication
Ambas envían datos del servidor al cliente, pero con diferentes garantías de fiabilidad:
- Notify (ATT_HANDLE_VALUE_NOTIFICATION): Sin confirmación. Latencia: ~3 ms/paquete en PHY 1 Mbps. Throughput: hasta 270 kbps con MTU 23 bytes, ~800 kbps con MTU 247 bytes.
- Indicate (ATT_HANDLE_VALUE_INDICATION): Requiere confirmación ATT del cliente. Añade un round-trip (~6–10 ms). Usar cuando la confirmación de entrega es obligatoria.
Para un módulo que stream datos de sensor a 10 Hz, Notify es la elección clara — la siguiente muestra sustituye cualquier paquete perdido. Para un módulo que reporta eventos de alarma, Indicate asegura que el cliente recibió la alerta.
Diseño de Descriptors
Cada characteristic que soporta Notify o Indicate debe incluir un Client Characteristic Configuration Descriptor (CCCD, UUID 0x2902). Escibir 0x0001 habilita Notify; 0x0002 habilita Indicate; 0x0000 deshabilita ambos.
Descriptors opcionales recomendados:
| Descriptor | UUID | Propósito |
|---|---|---|
| Characteristic User Description | 0x2901 | Nombre legible |
| Characteristic Presentation Format | 0x2904 | Unidad, exponente, tipo de dato |
| Characteristic Extended Properties | 0x2900 | Soporte Reliable Write |
El descriptor Presentation Format es especialmente valioso para módulos con múltiples tipos de sensor — permite a la aplicación cliente detectar automáticamente si un valor representa temperatura (0x07, unidades 0x272F = Celsius) o humedad (0x06, unidades 0x272F = porcentaje).
Optimización de MTU y Throughput
El MTU ATT predeterminado es 23 bytes (20 bytes payload). La mayoría de smartphones modernos soportan MTU 247 o superior. El módulo debe solicitar intercambio MTU durante la conexión:
// Pseudocódigo para negociación MTU ble_att_exchange_mtu_request(247); // Tras intercambio, MTU efectivo = min(local, remoto) // Payload por notificación = MTU - 3 bytes cabecera ATT
Comparación de throughput a diferentes valores MTU (intervalo 30 ms, PHY 1 Mbps):
| MTU | Payload/Paquete | Paquetes/Intervalo | Throughput |
|---|---|---|---|
| 23 | 20 B | 4 | 21 kbps |
| 185 | 182 B | 1 | 48 kbps |
| 247 | 244 B | 1 | 65 kbps |
Para módulos con Data Length Extension (DLE) (Bluetooth 4.2+), habilitar DLE junto con MTU grande puede superar 800 kbps en PHY 1 Mbps.
Ejemplo Práctico: Servicio Multi-Sensor
Diseño flat para un módulo con temperatura, humedad y acelerómetro:
Service: 6E400001-... (Custom Sensor Service) ├── Char: 6E400002-... (Temperature, Read|Notify) │ └── CCCD: 0x2902 │ └── Presentation Format: 0x2904 (int16, 0.01°C, unit Celsius) ├── Char: 6E400003-... (Humidity, Read|Notify) │ └── CCCD: 0x2902 │ └── Presentation Format: 0x2904 (uint16, 0.01%, unit percentage) ├── Char: 6E400004-... (Acceleration XYZ, Notify) │ └── CCCD: 0x2902 └── Char: 6E400005-... (Sampling Rate, Read|Write)
La characteristic Sampling Rate permite al cliente configurar la frecuencia de notificaciones — escribir 10 establece 10 Hz, escribir 0 deshabilita todas.
Impacto Energético
Cada notificación consume ~1.2 ms de tiempo activo de radio a 1 Mbps. A 10 Hz con payloads de 20 bytes:
- Tiempo radio activo: ~12 ms / 1000 ms = 1.2% duty cycle
- Corriente estimada: 0.012 × 8 mA (TX) + 0.988 × 5 µA (sleep) ≈ 100 µA promedio
- Vida batería CR2032 (220 mAh): ~2200 horas ≈ 91 días
Reduciendo a 1 Hz: corriente promedio baja a ~13 µA, extendiendo vida de batería a ~1.9 años.
Errores Comunes de Diseño
- Servicios excesivamente fragmentados: Dividir datos relacionados en múltiples servicios obliga al cliente a múltiples descubrimientos de servicio. Agrupar characteristics relacionadas en un solo servicio.
- CCCD ausente: Una characteristic con Notify pero sin CCCD causará que algunos stacks rechacen el servicio. Incluir siempre CCCD para characteristics notificables.
- Colisiones UUID: Usar UUIDs 128-bit aleatorios sin patrón base sistemático genera riesgo de colisiones entre variantes de producto. Adoptar UUID base con bytes inferiores secuenciales.
- Indications excesivas: Usar Indicate para datos de alta frecuencia (ej.: IMU 50 Hz) desperdicia bandwidth en confirmaciones. Reservar Indicate para eventos de baja frecuencia y alta fiabilidad.
- Ignorar Presentation Format: Sin descriptor 0x2904, las aplicaciones cliente deben hard-codear la interpretación de datos, rompiendo interoperabilidad con browsers GATT genéricos como nRF Connect.
Conclusión
La arquitectura de servicios GATT es el contrato de capa de aplicación entre un módulo Bluetooth y su host. Una organización de servicios pensada, selección apropiada de propiedades de characteristic, y uso correcto de descriptors determinan si un módulo se integra limpiamente en ecosistemas de terceros o se convierte en una carga de debugging. Los principios anteriores — diseño de servicio flat, Notify para streaming, asignación UUID sistemática, y optimización MTU — forman una base sólida para desarrollo de productos basados en módulos.