Zum Hauptinhalt springen

Android SDK Verwendung

Initialisierung

Verwenden Sie das Builder-Pattern, um eine SDK-Instanz zu erstellen. Die build()-Funktion ist eine suspend-Funktion, die DPoP-Schluesselpaar-Generierung, Token-Aktivierung und Berechtigungspruefung durchfuehrt.

import com.vitalera.sdk.VitaleraSdk

val sdk = VitaleraSdk.builder()
.context(applicationContext) // Auf Android erforderlich
.clientId("your-org-license-key") // Erforderlich -- von sdk@vitalera.com erhalten
.addProvider("omron") // Zu verwendende Anbieter deklarieren
.addProvider("polar")
.addProvider("standard-ble")
.connectedMode(true) // Optional: Patienten/Beobachtungs-API aktivieren
.build() // suspend: fuehrt DPoP-Auth + Berechtigungspruefung durch

Behandlung von Authentifizierungsfehlern bei der Initialisierung:

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)
}
}

Geraeteerkennung

Verwenden Sie DiscoveryFilter, um nach bestimmten Geraetetypen zu scannen. Die Erkennung gibt einen Kotlin Flow<DeviceDescriptor> zurueck, der erkannte Geraete ausgibt und nach dem Timeout abschliesst.

import com.vitalera.sdk.discovery.DiscoveryFilter
import com.vitalera.sdk.device.DeviceCapability

// Nach Blutdruckmessgeraeten ueber alle registrierten Anbieter scannen
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)")
}

Filteroptionen

// Nur Omron-Geraete
val omronFilter = DiscoveryFilter(providers = setOf("omron"))

// Nur Geraete, deren Name mit "Polar" beginnt
val polarFilter = DiscoveryFilter(namePrefix = "Polar")

// Kombiniert: Nur Polar-Herzfrequenzmesser
val combinedFilter = DiscoveryFilter(
providers = setOf("polar"),
capabilities = setOf(DeviceCapability.HEART_RATE),
)

Geraeteverbindung

Erstellen Sie ein Geraet aus einem DeviceDescriptor und verbinden Sie sich damit. Die connect()-Funktion ist eine suspend-Funktion mit konfigurierbarem Timeout.

val device = sdk.devices.createDevice(descriptor)

// Verbinden (suspendiert bis verbunden oder Timeout)
device.connect(timeoutMs = 10_000L)

// Verbindungsstatus reaktiv beobachten
launch {
device.connectionState.collect { state ->
when (state) {
is ConnectionState.Disconnected -> showStatus("Getrennt")
is ConnectionState.Connecting -> showStatus("Verbinde...")
is ConnectionState.Connected -> showStatus("Verbunden")
is ConnectionState.Disconnecting -> showStatus("Trenne: ${state.reason}")
is ConnectionState.Error -> showError(state.cause)
}
}
}

Datenerfassung

Die collect()-Methode gibt einen Flow<BaseObservation> typisierter Beobachtungsklassen zurueck. Bei Einzelmessungsgeraeten (z.B. Blutdruck) gibt der Flow eine Beobachtung aus und schliesst ab. Bei Streaming-Geraeten (z.B. Herzfrequenz) gibt er kontinuierlich aus.

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+ typisierte Beobachtungsklassen verfuegbar
}
}

// Nach Abschluss trennen
device.disconnect()

Connected Mode

Wenn connectedMode(true) bei der Initialisierung gesetzt ist, koennen Sie Patienten aufloesen und Beobachtungen an das Vitalera-Backend senden:

// Einen Patienten ueber externe Kennung aufloesen
val patient = sdk.connected().resolveMonitored("patient-ext-id")

// Eine Beobachtung senden
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"),
),
),
)

Fehlerbehandlung

Alle SDK-Fehler erweitern die versiegelte SdkError-Klasse:

try {
device.connect()
val obs = device.collect().first()
} catch (e: SdkError.ConnectionTimeout) {
showError("Verbindungszeitlimit ueberschritten. Bewegen Sie sich naeher zum Geraet.")
} catch (e: SdkError.BluetoothDisabled) {
showError("Bitte aktivieren Sie Bluetooth.")
} catch (e: SdkError.BluetoothPermissionDenied) {
showError("Bluetooth-Berechtigungen erforderlich.")
} catch (e: SdkError) {
showError("Geraetefehler: ${e.message}")
}

Mehrere Geraete

Verbinden Sie sich gleichzeitig mit mehreren Geraeten mithilfe von Coroutines:

val bpMonitor = sdk.devices.createDevice(bpDescriptor)
val hrMonitor = sdk.devices.createDevice(hrDescriptor)

coroutineScope {
launch { bpMonitor.connect() }
launch { hrMonitor.connect() }
}

Health Connect

Aus Google Health Connect lesen (kein BLE-Scanning erforderlich):

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()

Ressourcenbereinigung

Rufen Sie immer close() auf, wenn das SDK nicht mehr benoetigt wird:

sdk.close()  // Bricht Heartbeat ab, schliesst HTTP-Client, entsorgt Anbieter