From 8e1c8d14f5d5aeb30fd1d45a0bc533379b1c48d1 Mon Sep 17 00:00:00 2001 From: Gitea Date: Fri, 16 Oct 2026 20:48:39 +0200 Subject: [PATCH] made seperate BLE class --- .../smart_watch_android/BLE/BleManager.kt | 145 ++++++++++++++++++ .../smart_watch_android/BLE/DeviceUUIDs.kt | 8 + .../smart_watch_android/MainActivity.kt | 145 +----------------- 3 files changed, 160 insertions(+), 138 deletions(-) create mode 100644 app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt create mode 100644 app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt diff --git a/app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt b/app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt new file mode 100644 index 0000000..1c1a8a1 --- /dev/null +++ b/app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt @@ -0,0 +1,145 @@ +package com.example.smart_watch_android.BLE + +import android.Manifest +import android.app.Activity +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCallback +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothManager +import android.bluetooth.BluetoothProfile +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import androidx.annotation.RequiresPermission +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.core.app.ActivityCompat + +class BleManager(private val context: Context) { + val deviceUUIDs = DeviceUUIDs + private var bluetoothGatt: BluetoothGatt? = null + + private var bluetoothManager: BluetoothManager? = null + private var bluetoothAdapter: BluetoothAdapter? = null + + var isConnected by mutableStateOf(false) + private set + + fun init() { + bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager + bluetoothAdapter = bluetoothManager?.adapter + } + @RequiresApi(Build.VERSION_CODES.S) + fun checkAndRequestBluetoothPermissions() { + val permissions = arrayOf( + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.BLUETOOTH_SCAN, + Manifest.permission.ACCESS_FINE_LOCATION + ) + + // Prüfen, ob die Berechtigungen bereits erteilt wurden + val missingPermissions = permissions.filter { + ActivityCompat.checkSelfPermission(context, it) != PackageManager.PERMISSION_GRANTED + } + + if (missingPermissions.isNotEmpty()) { + // Wenn Berechtigungen fehlen, frage den Nutzer danach + ActivityCompat.requestPermissions(context as Activity, missingPermissions.toTypedArray(), 101) + } + } + + fun connectToEsp32(deviceAddress: String) { + Log.d("ESP32_BLE", "1. connectToEsp32 gestartet mit Adresse: $deviceAddress") + if (bluetoothAdapter == null) { + Log.d("ESP32_BLE", "Fehler: Bluetooth wird von diesem Gerät nicht unterstützt!") + return + } + + try { + val device = bluetoothAdapter!!.getRemoteDevice(deviceAddress) + Log.d("ESP32_BLE", "2. BluetoothDevice Objekt erfolgreich erstellt.") + + val gattCallback = object : BluetoothGattCallback() { + @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) + override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { + Log.d("ESP32_BLE", "3. onConnectionStateChange aufgerufen! Status: $status, NewState: $newState") + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + Log.d("ESP32_BLE", "4. Verbunden! Starte discoverServices()...") + gatt.discoverServices() + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + Log.d("ESP32_BLE", "5. Getrennt worden.") + isConnected = false + + gatt.close() + bluetoothGatt = null + } + } else { + Log.d("ESP32_BLE", "Fehler in onConnectionStateChange! Status-Code: $status") + isConnected = false + } + } + + override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { + Log.d("ESP32_BLE", "6. onServicesDiscovered aufgerufen mit Status: $status") + if (status == BluetoothGatt.GATT_SUCCESS) { + isConnected = true + writeToEsp32("Hallo ESP32") + Log.d("ESP32_BLE", "7. Services erfolgreich gefunden! Verbindung komplett erfolgreich.") + } + } + } + + // Berechtigungsprüfung + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { + Log.d("ESP32_BLE", "8. Berechtigung vorhanden, rufe connectGatt auf...") + bluetoothGatt = device.connectGatt(context, false, gattCallback) + } else { + Log.d("ESP32_BLE", "FEHLER: Keine BLUETOOTH_CONNECT Berechtigung erteilt!") + } + + } catch (e: Exception) { + Log.d("ESP32_BLE", "Exception gefangen: ${e.message}") + } + } + + fun writeToEsp32(dataString: String) { + // Prüfen, ob die Verbindung steht und bluetoothGatt nicht null ist + val gatt = bluetoothGatt + if (gatt == null) { + Log.d("ESP32_BLE", "Fehler: Kein GATT-Objekt vorhanden (nicht verbunden).") + return + } + + // 1. Service holen + val service = gatt.getService(deviceUUIDs.SERVICE_UUID) + if (service == null) { + Log.d("ESP32_BLE", "Fehler: Service UUID nicht gefunden!") + return + } + + // 2. Characteristic holen + val characteristic = service.getCharacteristic(deviceUUIDs.TIME_CHARACTERISTIC_UUID) + if (characteristic == null) { + Log.d("ESP32_BLE", "Fehler: Characteristic UUID nicht gefunden!") + return + } + + // 3. Daten in Bytes umwandeln (z.B. einen String wie "LED_ON" in UTF-8 Bytes) + val bytes = dataString.toByteArray(Charsets.UTF_8) + characteristic.value = bytes + + // 4. Schreibtyp festlegen ( WRITE_TYPE_DEFAULT wartet auf Antwort vom ESP32, WRITE_TYPE_NO_RESPONSE ist schneller ) + characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT + + // 5. Berechtigung prüfen und Schreibvorgang starten + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { + val success = gatt.writeCharacteristic(characteristic) + Log.d("ESP32_BLE", "Schreibvorgang gestartet: $success") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt b/app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt new file mode 100644 index 0000000..4f9362e --- /dev/null +++ b/app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt @@ -0,0 +1,8 @@ +package com.example.smart_watch_android.BLE + +import java.util.UUID + +object DeviceUUIDs { + val SERVICE_UUID = UUID.fromString("791cadd7-de87-49f9-8986-94b7ae11940b") + val TIME_CHARACTERISTIC_UUID = UUID.fromString("3e4eac5b-eaa2-4e0c-a705-dcac4f606e02") +} \ No newline at end of file diff --git a/app/src/main/java/com/example/smart_watch_android/MainActivity.kt b/app/src/main/java/com/example/smart_watch_android/MainActivity.kt index 08b75bd..f8dbb26 100644 --- a/app/src/main/java/com/example/smart_watch_android/MainActivity.kt +++ b/app/src/main/java/com/example/smart_watch_android/MainActivity.kt @@ -1,10 +1,9 @@ package com.example.smart_watch_android import android.Manifest -import android.app.Application -import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCallback +import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothProfile import android.content.Context @@ -17,156 +16,26 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.annotation.RequiresApi import androidx.annotation.RequiresPermission -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.core.app.ActivityCompat -import com.example.smart_watch_android.ui.theme.SmartWatchAndroidTheme -import java.util.UUID +import com.example.smart_watch_android.BLE.BleManager class MainActivity : ComponentActivity() { - private var bluetoothGatt: BluetoothGatt? = null - - var isConnected by mutableStateOf(false) - private set - - private val SERVICE_UUID = UUID.fromString("791cadd7-de87-49f9-8986-94b7ae11940b") - private val CHARACTERISTIC_UUID = UUID.fromString("3e4eac5b-eaa2-4e0c-a705-dcac4f606e02") - - - + val bleManager = BleManager(context = this) @RequiresApi(Build.VERSION_CODES.S) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - checkAndRequestBluetoothPermissions() + bleManager.init() + bleManager.checkAndRequestBluetoothPermissions() enableEdgeToEdge() setContent { ConnectCircleScreen( - isConnected = isConnected, + isConnected = bleManager.isConnected, onConnectClick = { Log.d("ESP32_BLE", "Button wurde gedrückt!") - connectToEsp32("10:BD:A3:8F:01:0E") + bleManager.connectToEsp32("10:BD:A3:8F:01:0E") } ) } } - @RequiresApi(Build.VERSION_CODES.S) - private fun checkAndRequestBluetoothPermissions() { - val permissions = arrayOf( - Manifest.permission.BLUETOOTH_CONNECT, - Manifest.permission.BLUETOOTH_SCAN, - Manifest.permission.ACCESS_FINE_LOCATION - ) - - // Prüfen, ob die Berechtigungen bereits erteilt wurden - val missingPermissions = permissions.filter { - ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED - } - - if (missingPermissions.isNotEmpty()) { - // Wenn Berechtigungen fehlen, frage den Nutzer danach - ActivityCompat.requestPermissions(this, missingPermissions.toTypedArray(), 101) - } - } - - private fun connectToEsp32(deviceAddress: String) { - Log.d("ESP32_BLE", "1. connectToEsp32 gestartet mit Adresse: $deviceAddress") - val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager - val bluetoothAdapter = bluetoothManager.adapter - if (bluetoothAdapter == null) { - Log.d("ESP32_BLE", "Fehler: Bluetooth wird von diesem Gerät nicht unterstützt!") - return - } - - try { - val device = bluetoothAdapter.getRemoteDevice(deviceAddress) - Log.d("ESP32_BLE", "2. BluetoothDevice Objekt erfolgreich erstellt.") - - val gattCallback = object : BluetoothGattCallback() { - @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) - override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { - Log.d("ESP32_BLE", "3. onConnectionStateChange aufgerufen! Status: $status, NewState: $newState") - if (status == BluetoothGatt.GATT_SUCCESS) { - if (newState == BluetoothProfile.STATE_CONNECTED) { - Log.d("ESP32_BLE", "4. Verbunden! Starte discoverServices()...") - gatt.discoverServices() - } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { - Log.d("ESP32_BLE", "5. Getrennt worden.") - isConnected = false - - gatt.close() - bluetoothGatt = null - } - } else { - Log.d("ESP32_BLE", "Fehler in onConnectionStateChange! Status-Code: $status") - isConnected = false - } - } - - override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { - Log.d("ESP32_BLE", "6. onServicesDiscovered aufgerufen mit Status: $status") - if (status == BluetoothGatt.GATT_SUCCESS) { - isConnected = true - writeToEsp32("Hallo ESP32") - Log.d("ESP32_BLE", "7. Services erfolgreich gefunden! Verbindung komplett erfolgreich.") - } - } - } - - // Berechtigungsprüfung - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { - Log.d("ESP32_BLE", "8. Berechtigung vorhanden, rufe connectGatt auf...") - bluetoothGatt = device.connectGatt(this, false, gattCallback) - } else { - Log.d("ESP32_BLE", "FEHLER: Keine BLUETOOTH_CONNECT Berechtigung erteilt!") - } - - } catch (e: Exception) { - Log.d("ESP32_BLE", "Exception gefangen: ${e.message}") - } - } - - private fun writeToEsp32(dataString: String) { - // Prüfen, ob die Verbindung steht und bluetoothGatt nicht null ist - val gatt = bluetoothGatt - if (gatt == null) { - Log.d("ESP32_BLE", "Fehler: Kein GATT-Objekt vorhanden (nicht verbunden).") - return - } - - // 1. Service holen - val service = gatt.getService(SERVICE_UUID) - if (service == null) { - Log.d("ESP32_BLE", "Fehler: Service UUID nicht gefunden!") - return - } - - // 2. Characteristic holen - val characteristic = service.getCharacteristic(CHARACTERISTIC_UUID) - if (characteristic == null) { - Log.d("ESP32_BLE", "Fehler: Characteristic UUID nicht gefunden!") - return - } - - // 3. Daten in Bytes umwandeln (z.B. einen String wie "LED_ON" in UTF-8 Bytes) - val bytes = dataString.toByteArray(Charsets.UTF_8) - characteristic.value = bytes - - // 4. Schreibtyp festlegen ( WRITE_TYPE_DEFAULT wartet auf Antwort vom ESP32, WRITE_TYPE_NO_RESPONSE ist schneller ) - characteristic.writeType = android.bluetooth.BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT - - // 5. Berechtigung prüfen und Schreibvorgang starten - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { - val success = gatt.writeCharacteristic(characteristic) - Log.d("ESP32_BLE", "Schreibvorgang gestartet: $success") - } - } }