Ús del SDK Android
Inicialització
Utilitzeu el patró builder per crear una instància del SDK. La funció build() és una funció suspend que realitza la generació del parell de claus DPoP, l'activació del token i la verificació de drets.
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
Gestioneu errors d'autenticació durant la inicialització:
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)
}
}
Descobriment de dispositius
Utilitzeu DiscoveryFilter per escanejar tipus específics de dispositius. El descobriment retorna un Kotlin Flow<DeviceDescriptor> que emet dispositius descoberts i completa després del temps d'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)")
}
Opcions de filtre
// 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),
)
Connexió de dispositius
Creeu un dispositiu a partir d'un DeviceDescriptor i connecteu-vos-hi. La funció connect() és una funció suspend amb un temps d'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)
}
}
}
Recollida de dades
El mètode collect() retorna un Flow<BaseObservation> de classes d'observació tipades. Per a dispositius de lectura única (p. ex., pressió arterial), el Flow emet una observació i completa. Per a dispositius de streaming (p. ex., freqüència cardíaca), emet contínuament.
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()
Mode connectat
Quan connectedMode(true) s'estableix durant la inicialització, resolveu pacients i envieu observacions 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ó d'errors
Tots els errors del SDK estenen la classe segellada 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 dispositius
Connecteu-vos a múltiples dispositius simultàniament utilitzant corrutines:
val bpMonitor = sdk.devices.createDevice(bpDescriptor)
val hrMonitor = sdk.devices.createDevice(hrDescriptor)
coroutineScope {
launch { bpMonitor.connect() }
launch { hrMonitor.connect() }
}
Health Connect
Llegiu de Google Health Connect (no es requereix escaneig 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()
Neteja de recursos
Crideu sempre close() quan el SDK ja no sigui necessari:
sdk.close() // Cancels heartbeat, closes HTTP client, disposes providers