Uso del SDK Android
Inicialización
Utilice el patrón builder para crear una instancia del SDK. La función build() es una función suspend que realiza la generación del par de claves DPoP, la activación del token y la verificación de permisos.
import com.vitalera.sdk.VitaleraSdk
val sdk = VitaleraSdk.builder()
.context(applicationContext) // Required on Android
.clientId("your-org-license-key") // Required -- obtain from sdk@vitalera.com
.addProvider("omron") // Declare which providers to use
.addProvider("polar")
.addProvider("standard-ble")
.connectedMode(true) // Optional: enable patient/observation API
.build() // suspend: performs DPoP auth + entitlement check
Gestione los errores de autenticación durante la inicialización:
try {
val sdk = VitaleraSdk.builder()
.context(applicationContext)
.clientId("your-org-license-key")
.build()
} catch (e: SdkAuthException) {
when (e.errorCode) {
"activation_failed" -> showInvalidLicenseError()
"entitlements_expired" -> showConnectToInternetPrompt()
"no_cache" -> showFirstLaunchOfflineError()
else -> showGenericError(e.message)
}
}
Descubrimiento de dispositivos
Utilice DiscoveryFilter para escanear tipos de dispositivos específicos. El descubrimiento devuelve un Kotlin Flow<DeviceDescriptor> que emite dispositivos descubiertos y se completa tras el tiempo de espera.
import com.vitalera.sdk.discovery.DiscoveryFilter
import com.vitalera.sdk.device.DeviceCapability
// Scan for blood pressure monitors across all registered providers
val filter = DiscoveryFilter(
capabilities = setOf(DeviceCapability.BLOOD_PRESSURE)
)
sdk.devices.discover(filter, timeoutMs = 15_000L).collect { descriptor ->
// descriptor: DeviceDescriptor(id, name, provider, modelId, rssi, capabilities)
println("Found: ${descriptor.name} (${descriptor.provider}, ${descriptor.rssi} dBm)")
}
Opciones de filtrado
// Only Omron devices
val omronFilter = DiscoveryFilter(providers = setOf("omron"))
// Only devices whose name starts with "Polar"
val polarFilter = DiscoveryFilter(namePrefix = "Polar")
// Combine: Polar heart rate monitors only
val combinedFilter = DiscoveryFilter(
providers = setOf("polar"),
capabilities = setOf(DeviceCapability.HEART_RATE),
)
Conexión de dispositivos
Cree un dispositivo a partir de un DeviceDescriptor y conéctese a él. La función connect() es una función suspend con un tiempo de espera configurable.
val device = sdk.devices.createDevice(descriptor)
// Connect (suspends until connected or timeout)
device.connect(timeoutMs = 10_000L)
// Observe connection state reactively
launch {
device.connectionState.collect { state ->
when (state) {
is ConnectionState.Disconnected -> showStatus("Disconnected")
is ConnectionState.Connecting -> showStatus("Connecting...")
is ConnectionState.Connected -> showStatus("Connected")
is ConnectionState.Disconnecting -> showStatus("Disconnecting: ${state.reason}")
is ConnectionState.Error -> showError(state.cause)
}
}
}
Recopilación de datos
El método collect() devuelve un Flow<BaseObservation> de clases de observación tipadas. Para dispositivos de lectura única (p. ej., presión arterial), el Flow emite una observación y se completa. Para dispositivos de streaming (p. ej., frecuencia cardíaca), emite continuamente.
device.collect().collect { observation ->
when (observation) {
is BloodPressureObservation -> {
val systolic = observation.systolic
val diastolic = observation.diastolic
val pulseRate = observation.pulseRate
val irregular = observation.irregularPulseDetected
}
is HeartRateObservation -> {
val bpm = observation.heartRate
}
is WeightObservation -> {
val kg = observation.weight
}
is TemperatureObservation -> {
val celsius = observation.temperature
}
is OxygenSaturationObservation -> {
val spo2 = observation.spo2
}
is BloodGlucoseObservation -> {
val glucose = observation.glucose
}
// 30+ typed observation classes available
}
}
// Disconnect when done
device.disconnect()
Modo conectado
Cuando se establece connectedMode(true) durante la inicialización, resuelva pacientes y envíe observaciones al backend de vitalera:
// Resolve a patient by external identifier
val patient = sdk.connected().resolveMonitored("patient-ext-id")
// Post an observation
sdk.connected().postObservation(
monitoredId = patient.id,
observation = BaseObservation(
observationType = "blood-pressure",
issued = Clock.System.now().toString(),
components = listOf(
ObservationComponent(name = "systolic", value = "120", valueUnit = "mmHg"),
ObservationComponent(name = "diastolic", value = "80", valueUnit = "mmHg"),
),
),
)
Gestión de errores
Todos los errores del SDK extienden la clase sellada SdkError:
try {
device.connect()
val obs = device.collect().first()
} catch (e: SdkError.ConnectionTimeout) {
showError("Connection timed out. Move closer to the device.")
} catch (e: SdkError.BluetoothDisabled) {
showError("Please enable Bluetooth.")
} catch (e: SdkError.BluetoothPermissionDenied) {
showError("Bluetooth permissions required.")
} catch (e: SdkError) {
showError("Device error: ${e.message}")
}
Múltiples dispositivos
Conéctese a múltiples dispositivos simultáneamente utilizando corrutinas:
val bpMonitor = sdk.devices.createDevice(bpDescriptor)
val hrMonitor = sdk.devices.createDevice(hrDescriptor)
coroutineScope {
launch { bpMonitor.connect() }
launch { hrMonitor.connect() }
}
Health Connect
Lea de Google Health Connect (no requiere escaneo BLE):
val descriptor = sdk.devices.discover(
DiscoveryFilter(providers = setOf("health-connect")),
timeoutMs = 5_000L,
).first()
val store = sdk.devices.createDevice(descriptor)
store.connect()
val observations = store.collect().toList()
store.disconnect()
Liberación de recursos
Llame siempre a close() cuando el SDK ya no sea necesario:
sdk.close() // Cancels heartbeat, closes HTTP client, disposes providers