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.