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.setValue
|
||||
import androidx.core.app.ActivityCompat
|
||||
import java.util.UUID
|
||||
|
||||
class BleManager(private val context: Context) {
|
||||
val deviceUUIDs = DeviceUUIDs
|
||||
@@ -72,11 +73,11 @@ class BleManager(private val context: Context) {
|
||||
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
|
||||
Log.d("ESP32_BLE", "5. Getrennt worden.")
|
||||
}
|
||||
} else {
|
||||
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")
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
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.")
|
||||
}
|
||||
}
|
||||
@@ -106,8 +107,20 @@ class BleManager(private val context: Context) {
|
||||
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
|
||||
val gatt = bluetoothGatt
|
||||
if (gatt == null) {
|
||||
@@ -116,14 +129,14 @@ class BleManager(private val context: Context) {
|
||||
}
|
||||
|
||||
// 1. Service holen
|
||||
val service = gatt.getService(deviceUUIDs.SERVICE_UUID)
|
||||
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(deviceUUIDs.TIME_CHARACTERISTIC_UUID)
|
||||
val characteristic = service.getCharacteristic(TIME_CHARACTERISTIC_UUID)
|
||||
if (characteristic == null) {
|
||||
Log.d("ESP32_BLE", "Fehler: Characteristic UUID nicht gefunden!")
|
||||
return
|
||||
|
||||
@@ -3,6 +3,6 @@ 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")
|
||||
val SERVICE_UUID: UUID? = UUID.fromString("791cadd7-de87-49f9-8986-94b7ae11940b")
|
||||
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
|
||||
|
||||
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.Bundle
|
||||
import android.util.Log
|
||||
@@ -15,8 +7,10 @@ import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.example.smart_watch_android.BLE.BleManager
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
@@ -29,13 +23,16 @@ class MainActivity : ComponentActivity() {
|
||||
bleManager.checkAndRequestBluetoothPermissions()
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
ConnectCircleScreen(
|
||||
isConnected = bleManager.isConnected,
|
||||
onConnectClick = {
|
||||
Log.d("ESP32_BLE", "Button wurde gedrückt!")
|
||||
bleManager.connectToEsp32("10:BD:A3:8F:01:0E")
|
||||
MaterialTheme {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
// 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