sending of message and working connect/disconnect
This commit is contained in:
1 parent
8e1c8d14f5
commit
21883af93b
7 files changed
+206
-69
No files matched your search
@@ -18,6 +18,7 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
class BleManager(private val context: Context) {
|
class BleManager(private val context: Context) {
|
||||||
val deviceUUIDs = DeviceUUIDs
|
val deviceUUIDs = DeviceUUIDs
|
||||||
@@ -72,11 +73,11 @@ class BleManager(private val context: Context) {
|
|||||||
Log.d("ESP32_BLE", "4. Verbunden! Starte discoverServices()...")
|
Log.d("ESP32_BLE", "4. Verbunden! Starte discoverServices()...")
|
||||||
gatt.discoverServices()
|
gatt.discoverServices()
|
||||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||||
Log.d("ESP32_BLE", "5. Getrennt worden.")
|
|
||||||
isConnected = false
|
isConnected = false
|
||||||
|
|
||||||
gatt.close()
|
gatt.close()
|
||||||
bluetoothGatt = null
|
bluetoothGatt = null
|
||||||
|
Log.d("ESP32_BLE", "5. Getrennt worden.")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d("ESP32_BLE", "Fehler in onConnectionStateChange! Status-Code: $status")
|
Log.d("ESP32_BLE", "Fehler in onConnectionStateChange! Status-Code: $status")
|
||||||
@@ -88,7 +89,7 @@ class BleManager(private val context: Context) {
|
|||||||
Log.d("ESP32_BLE", "6. onServicesDiscovered aufgerufen mit Status: $status")
|
Log.d("ESP32_BLE", "6. onServicesDiscovered aufgerufen mit Status: $status")
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
isConnected = true
|
isConnected = true
|
||||||
writeToEsp32("Hallo ESP32")
|
writeToEsp32("Hallo ESP32", deviceUUIDs.TIME_CHARACTERISTIC_UUID, deviceUUIDs.TIME_CHARACTERISTIC_UUID)
|
||||||
Log.d("ESP32_BLE", "7. Services erfolgreich gefunden! Verbindung komplett erfolgreich.")
|
Log.d("ESP32_BLE", "7. Services erfolgreich gefunden! Verbindung komplett erfolgreich.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,8 +107,20 @@ class BleManager(private val context: Context) {
|
|||||||
Log.d("ESP32_BLE", "Exception gefangen: ${e.message}")
|
Log.d("ESP32_BLE", "Exception gefangen: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
|
||||||
|
fun disconnectEsp32() {
|
||||||
|
// Nur den Disconnect-Befehl senden.
|
||||||
|
// Das Schließen (close) überlassen wir dem Callback, wenn es wirklich so weit ist!
|
||||||
|
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
bluetoothGatt?.disconnect()
|
||||||
|
Log.d("ESP32_BLE","disconnectEsp32")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log.d("BLE_DEBUG", "Permission BLUETOOTH_CONNECT fehlt!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun writeToEsp32(dataString: String) {
|
fun writeToEsp32(dataString: String, SERVICE_UUID: UUID?, TIME_CHARACTERISTIC_UUID: UUID?) {
|
||||||
// Prüfen, ob die Verbindung steht und bluetoothGatt nicht null ist
|
// Prüfen, ob die Verbindung steht und bluetoothGatt nicht null ist
|
||||||
val gatt = bluetoothGatt
|
val gatt = bluetoothGatt
|
||||||
if (gatt == null) {
|
if (gatt == null) {
|
||||||
@@ -116,14 +129,14 @@ class BleManager(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. Service holen
|
// 1. Service holen
|
||||||
val service = gatt.getService(deviceUUIDs.SERVICE_UUID)
|
val service = gatt.getService(SERVICE_UUID)
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
Log.d("ESP32_BLE", "Fehler: Service UUID nicht gefunden!")
|
Log.d("ESP32_BLE", "Fehler: Service UUID nicht gefunden!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Characteristic holen
|
// 2. Characteristic holen
|
||||||
val characteristic = service.getCharacteristic(deviceUUIDs.TIME_CHARACTERISTIC_UUID)
|
val characteristic = service.getCharacteristic(TIME_CHARACTERISTIC_UUID)
|
||||||
if (characteristic == null) {
|
if (characteristic == null) {
|
||||||
Log.d("ESP32_BLE", "Fehler: Characteristic UUID nicht gefunden!")
|
Log.d("ESP32_BLE", "Fehler: Characteristic UUID nicht gefunden!")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ package com.example.smart_watch_android.BLE
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
object DeviceUUIDs {
|
object DeviceUUIDs {
|
||||||
val SERVICE_UUID = UUID.fromString("791cadd7-de87-49f9-8986-94b7ae11940b")
|
val SERVICE_UUID: UUID? = UUID.fromString("791cadd7-de87-49f9-8986-94b7ae11940b")
|
||||||
val TIME_CHARACTERISTIC_UUID = UUID.fromString("3e4eac5b-eaa2-4e0c-a705-dcac4f606e02")
|
val TIME_CHARACTERISTIC_UUID: UUID? = UUID.fromString("3e4eac5b-eaa2-4e0c-a705-dcac4f606e02")
|
||||||
}
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package com.example.smart_watch_android
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ConnectCircleScreen(
|
|
||||||
isConnected: Boolean,
|
|
||||||
onConnectClick: () -> Unit
|
|
||||||
) {
|
|
||||||
// Ein Container, der den gesamten Bildschirm ausfüllt
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center // Zentriert den Inhalt exakt in der Mitte
|
|
||||||
) {
|
|
||||||
// Der Kreis-Button
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(180.dp) // Größe des Kreises
|
|
||||||
.clip(CircleShape) // Macht das Element zu einem perfekten Kreis
|
|
||||||
.background(if (isConnected) Color.Green else Color.Blue) // Grün = verbunden, Blau = Start/Verbinden
|
|
||||||
.clickable { onConnectClick() }, // Was passiert beim Drücken
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = if (isConnected) "Verbunden" else "Connect",
|
|
||||||
color = Color.White,
|
|
||||||
fontSize = 20.sp,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,5 @@
|
|||||||
package com.example.smart_watch_android
|
package com.example.smart_watch_android
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
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.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@@ -15,8 +7,10 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.annotation.RequiresPermission
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
import com.example.smart_watch_android.BLE.BleManager
|
import com.example.smart_watch_android.BLE.BleManager
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
@@ -29,13 +23,16 @@ class MainActivity : ComponentActivity() {
|
|||||||
bleManager.checkAndRequestBluetoothPermissions()
|
bleManager.checkAndRequestBluetoothPermissions()
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
ConnectCircleScreen(
|
MaterialTheme {
|
||||||
isConnected = bleManager.isConnected,
|
Surface(
|
||||||
onConnectClick = {
|
modifier = Modifier.fillMaxSize(),
|
||||||
Log.d("ESP32_BLE", "Button wurde gedrückt!")
|
color = MaterialTheme.colorScheme.background
|
||||||
bleManager.connectToEsp32("10:BD:A3:8F:01:0E")
|
) {
|
||||||
|
// Hier wird deine AppNavigation aufgerufen,
|
||||||
|
// die die Screens steuert!
|
||||||
|
AppNavigation(bleManager)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.example.smart_watch_android.Screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ConnectScreen(isConnected: Boolean, onConnectClicked: () -> Unit) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onConnectClicked,
|
||||||
|
colors = if (isConnected) {
|
||||||
|
ButtonDefaults.buttonColors(containerColor = Color(0xFF4CAF50)) // Grün
|
||||||
|
} else {
|
||||||
|
ButtonDefaults.buttonColors()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(text = if (isConnected) "Verbunden" else "Connect")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.example.smart_watch_android.Screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.smart_watch_android.BLE.BleManager
|
||||||
|
import com.example.smart_watch_android.BLE.DeviceUUIDs
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ControlPanelScreen(
|
||||||
|
bleManager: BleManager,
|
||||||
|
onDisconnectClicked: () -> Unit
|
||||||
|
) {
|
||||||
|
var textInput by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
// Eingabefeld für Text / Uhrzeit / Befehle
|
||||||
|
OutlinedTextField(
|
||||||
|
value = textInput,
|
||||||
|
onValueChange = { textInput = it },
|
||||||
|
label = { Text("Nachricht an ESP32") },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Send Button
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (textInput.isNotEmpty()) {
|
||||||
|
bleManager.writeToEsp32(
|
||||||
|
textInput, DeviceUUIDs.SERVICE_UUID, DeviceUUIDs.TIME_CHARACTERISTIC_UUID
|
||||||
|
)
|
||||||
|
textInput = "" // Feld danach leeren
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("Send")
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
|
// Disconnect Button (z.B. in Rot, um ihn abzusetzen)
|
||||||
|
Button(
|
||||||
|
onClick = onDisconnectClicked,
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE53935)),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("Disconnect")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.example.smart_watch_android
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.smart_watch_android.BLE.BleManager
|
||||||
|
import com.example.smart_watch_android.BLE.DeviceUUIDs
|
||||||
|
import com.example.smart_watch_android.Screens.ConnectScreen
|
||||||
|
import com.example.smart_watch_android.Screens.ControlPanelScreen
|
||||||
|
|
||||||
|
enum class Screen {
|
||||||
|
CONNECT,
|
||||||
|
CONTROL_PANEL
|
||||||
|
}
|
||||||
|
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
|
||||||
|
@Composable
|
||||||
|
fun AppNavigation(BLEManager: BleManager) {
|
||||||
|
var currentScreen by remember { mutableStateOf(Screen.CONNECT) }
|
||||||
|
val bleManager = BLEManager
|
||||||
|
|
||||||
|
if (bleManager.isConnected && currentScreen == Screen.CONNECT) {
|
||||||
|
currentScreen = Screen.CONTROL_PANEL
|
||||||
|
} else if (!bleManager.isConnected && currentScreen == Screen.CONTROL_PANEL) {
|
||||||
|
currentScreen = Screen.CONNECT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Je nach Zustand den entsprechenden Screen anzeigen
|
||||||
|
when (currentScreen) {
|
||||||
|
Screen.CONNECT -> {
|
||||||
|
ConnectScreen(
|
||||||
|
isConnected = bleManager.isConnected,
|
||||||
|
onConnectClicked = {
|
||||||
|
bleManager.connectToEsp32("10:BD:A3:8F:01:0E")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Screen.CONTROL_PANEL -> {
|
||||||
|
ControlPanelScreen(
|
||||||
|
bleManager,
|
||||||
|
onDisconnectClicked = {
|
||||||
|
bleManager.disconnectEsp32()
|
||||||
|
// Screen wechselt automatisch über den Check oben
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user