From eb573980b92966bd60af92aa1fa00b0ea389ebb0 Mon Sep 17 00:00:00 2001 From: EndikaCo Date: Tue, 9 Jan 2024 13:00:52 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B:=20Fix=20update=20connected=20devi?= =?UTF-8?q?ce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix update connected device from previous commit --- README.md | 10 ++--- .../data/bluetooth/BluetoothController.kt | 45 +++---------------- .../mappers/BluetoothMessageMapper.kt | 18 +++----- .../data/model/BluetoothMessage.kt | 6 --- .../data/model/BluetoothUiState.kt | 11 ----- .../bluetooth_bike/data/model/BtDevice.kt | 10 ----- .../domain/bluetooth/BluetoothController.kt | 4 +- .../bluetooth_bike/domain/model/BtMessage.kt | 1 - .../bluetooth_bike/domain/model/UiState.kt | 2 +- .../ui/components/BatteryInfoView.kt | 6 +-- .../ui/components/BatteryValuesChart.kt | 38 ++++++++++------ .../bluetooth_bike/ui/screens/BikeScreen.kt | 20 ++++----- .../ui/viewmodels/BluetoothViewModel.kt | 1 + .../mappers/BluetoothMessageMapperKtTest.kt | 10 ++--- .../bluetooth_bike/ui/MainActivityTest.kt | 8 ---- build.gradle.kts | 2 +- 16 files changed, 63 insertions(+), 129 deletions(-) delete mode 100644 app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothMessage.kt delete mode 100644 app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothUiState.kt delete mode 100644 app/src/main/java/com/example/bluetooth_bike/data/model/BtDevice.kt delete mode 100644 app/src/test/java/com/example/bluetooth_bike/ui/MainActivityTest.kt diff --git a/README.md b/README.md index 39fcc6a..98c440d 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ Bluetooth Ebike connector ===== -[![Android](https://img.shields.io/badge/Android-grey?style=&logo=android&logoColor=green)](https://www.android.com/) -[![KOTLIN](https://img.shields.io/badge/Kotlin-grey?style=none&logo=Kotlin&logoColor=-5C2D91)](https://kotlinlang.org/) -[![CI](https://github.com/EndikaCo/Bluetooth_bike/actions/workflows/testing.yml/badge.svg)]() [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/EndikaCo/Bluetooth_bike/LICENSE) +[![CI](https://github.com/EndikaCo/Bluetooth_bike/actions/workflows/testing.yml/badge.svg)]() Simple app to connect to a Ebike via bluetooth, get the data from it, and send commands back to interact with it. -[![Compose](https://img.shields.io/badge/Jetpack_Compose-grey?style=none&logo=)](https://kotlinlang.org/) +[![Android](https://img.shields.io/badge/Android-grey?style=&logo=android&logoColor=green)](https://www.android.com/) +[![KOTLIN](https://img.shields.io/badge/Kotlin-grey?style=none&logo=Kotlin&logoColor=-5C2D91)](https://kotlinlang.org/) +[![Compose](https://img.shields.io/badge/Jetpack_Compose-blue?style=none&logo=)](https://kotlinlang.org/) [![Bluetooth](https://img.shields.io/badge/bluetooth-grey?style=none&logo=bluetooth&logoColor=white)]() [![Dagger](https://img.shields.io/badge/Dagger_Hilt-grey?style=&logo=)]() -[![MVVM](https://img.shields.io/badge/MVVM-grey?style=&logo=)]() +[![MVVM](https://img.shields.io/badge/MVVM-orange?style=&logo=)]() [![State Flow](https://img.shields.io/badge/State_Flow-grey?style=&logo=)]() [![Canvas](https://img.shields.io/badge/canvas-grey?style=none&logo=canvas&logoColor=white)]() diff --git a/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/BluetoothController.kt b/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/BluetoothController.kt index 80211a7..87d96c6 100644 --- a/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/BluetoothController.kt +++ b/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/BluetoothController.kt @@ -67,6 +67,11 @@ class BluetoothController( override val errors: SharedFlow get() = _errors.asSharedFlow() + private val _connectedDeviceName = MutableStateFlow("") + override val connectedDeviceName: StateFlow + get() = _connectedDeviceName.asStateFlow() + + private val scanDeviceReceiver = ScanDeviceReceiver { device -> _devices.update { devices -> val newDevice = device.toBtDeviceDomain(isPaired = false) @@ -103,6 +108,7 @@ class BluetoothController( private val bluetoothStateReceiver = BluetoothStateReceiver { isConnected, bluetoothDevice -> if (bluetoothAdapter?.bondedDevices?.contains(bluetoothDevice) == true) { _isConnected.update { isConnected } + _connectedDeviceName.update { if (isConnected) bluetoothDevice.name ?: "" else "Unknown" } } else { CoroutineScope(Dispatchers.IO).launch { _errors.emit("Can't connect to a non-paired device.") @@ -155,45 +161,6 @@ class BluetoothController( bluetoothAdapter?.cancelDiscovery() } - override fun startBluetoothServer(): Flow { - return flow { - if (!hasPermission(Manifest.permission.BLUETOOTH_CONNECT)) { - throw SecurityException("No BLUETOOTH_CONNECT permission") - } - - currentServerSocket = bluetoothAdapter?.listenUsingRfcommWithServiceRecord( - "chat_service", - UUID.fromString(SERVICE_UUID) - ) - - var shouldLoop = true - while (shouldLoop) { - currentClientSocket = try { - currentServerSocket?.accept() - } catch (e: IOException) { - shouldLoop = false - null - } - emit(ConnectionResult.ConnectionEstablished) - currentClientSocket?.let { socket -> - currentServerSocket?.close() - val service = BluetoothDataTransferService(socket) - dataTransferService = service - - emitAll( - service - .listenForIncomingMessages() - .map { - ConnectionResult.TransferSucceeded(it) - } - ) - } - } - }.onCompletion { - closeConnection() - }.flowOn(Dispatchers.IO) - } - override fun connectToDevice(device: BtDevice): Flow { return flow { if (!hasPermission(Manifest.permission.BLUETOOTH_CONNECT)) { diff --git a/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapper.kt b/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapper.kt index 3c9370d..ddaf1a3 100644 --- a/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapper.kt +++ b/app/src/main/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapper.kt @@ -3,18 +3,12 @@ package com.example.bluetooth_bike.data.bluetooth.mappers import com.example.bluetooth_bike.domain.model.BtMessage fun String.toBtMessage(): BtMessage { - val name = substringBefore("#") - val voltage = substringAfter("#").substringBefore("$") - val amperes = substringAfter("$").substringBefore("%") - val speed = substringAfter("%").substringBefore("&") - val trip = substringAfter("&").substringBefore("*") - val total = substringAfter("*") + val parts = this.split("#", "$", "%", "&", "*") return BtMessage( - voltage = voltage, - amperes = amperes, - speed = speed, - trip = trip, - total = total, - senderName = name, + voltage = parts.getOrNull(1) ?: "", + amperes = parts.getOrNull(2) ?: "", + speed = parts.getOrNull(3) ?: "", + trip = parts.getOrNull(4) ?: "", + total = parts.getOrNull(5) ?: "", ) } \ No newline at end of file diff --git a/app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothMessage.kt b/app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothMessage.kt deleted file mode 100644 index 3b91dc8..0000000 --- a/app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothMessage.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.bluetooth_bike.data.model - -data class BluetoothMessage( - val message: String, - val senderName: String, -) \ No newline at end of file diff --git a/app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothUiState.kt b/app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothUiState.kt deleted file mode 100644 index 6ebb9f5..0000000 --- a/app/src/main/java/com/example/bluetooth_bike/data/model/BluetoothUiState.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.example.bluetooth_bike.data.model - -data class BluetoothUiState( - val scannedDevices: List = emptyList(), - val pairedDevices: List = emptyList(), - val isScanning : Boolean = false, - val isConnected : Boolean = false, - val isConnecting : Boolean = false, - val errorMessage : String? = null, - val messages: List = emptyList() -) diff --git a/app/src/main/java/com/example/bluetooth_bike/data/model/BtDevice.kt b/app/src/main/java/com/example/bluetooth_bike/data/model/BtDevice.kt deleted file mode 100644 index e9b488f..0000000 --- a/app/src/main/java/com/example/bluetooth_bike/data/model/BtDevice.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.bluetooth_bike.data.model - -import android.bluetooth.BluetoothClass - -data class BtDevice( - val name: String?, - val address: String, - val btType: Int, - val btClass: BluetoothClass -) \ No newline at end of file diff --git a/app/src/main/java/com/example/bluetooth_bike/domain/bluetooth/BluetoothController.kt b/app/src/main/java/com/example/bluetooth_bike/domain/bluetooth/BluetoothController.kt index 4cdcbf5..5d18ae7 100644 --- a/app/src/main/java/com/example/bluetooth_bike/domain/bluetooth/BluetoothController.kt +++ b/app/src/main/java/com/example/bluetooth_bike/domain/bluetooth/BluetoothController.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow interface BluetoothController { + val connectedDeviceName: StateFlow val devices: StateFlow> val isScanning: StateFlow val isConnected: StateFlow @@ -13,9 +14,8 @@ interface BluetoothController { fun startDiscovery() fun stopDiscovery() - fun startBluetoothServer(): Flow fun connectToDevice(device: BtDevice): Flow - suspend fun trySendMessage(message : String) : String? + suspend fun trySendMessage(message: String): String? fun closeConnection() fun release() } \ No newline at end of file diff --git a/app/src/main/java/com/example/bluetooth_bike/domain/model/BtMessage.kt b/app/src/main/java/com/example/bluetooth_bike/domain/model/BtMessage.kt index 4c50c6d..2820633 100644 --- a/app/src/main/java/com/example/bluetooth_bike/domain/model/BtMessage.kt +++ b/app/src/main/java/com/example/bluetooth_bike/domain/model/BtMessage.kt @@ -6,5 +6,4 @@ data class BtMessage( val speed: String, val trip : String, val total : String, - val senderName: String, ) \ No newline at end of file diff --git a/app/src/main/java/com/example/bluetooth_bike/domain/model/UiState.kt b/app/src/main/java/com/example/bluetooth_bike/domain/model/UiState.kt index 2930ab9..d838d62 100644 --- a/app/src/main/java/com/example/bluetooth_bike/domain/model/UiState.kt +++ b/app/src/main/java/com/example/bluetooth_bike/domain/model/UiState.kt @@ -14,8 +14,8 @@ data class UiState( speed = "00", trip = "0.0", total = "0.0", - senderName = "-", ) ), val time : TimeModel = TimeModel(), + val connectedDevice : BtDevice? = null, ) diff --git a/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryInfoView.kt b/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryInfoView.kt index 21f0745..9b42009 100644 --- a/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryInfoView.kt +++ b/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryInfoView.kt @@ -81,7 +81,7 @@ fun PreviewBatteryInfoView() { speed = "10", trip = "10", total = "10", - senderName = "test") + ) BatteryInfoView(mockData) } @@ -96,7 +96,7 @@ fun PreviewBatteryInfoView2() { speed = "10", trip = "10.50", total = "101.50", - senderName = "test") + ) BatteryInfoView(mockData) } @@ -112,6 +112,6 @@ fun PreviewBatteryInfoView3() { speed = "10", trip = "10.50", total = "101.50", - senderName = "test") + ) BatteryInfoView(mockData)} } \ No newline at end of file diff --git a/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryValuesChart.kt b/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryValuesChart.kt index cf9d342..02d1dca 100644 --- a/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryValuesChart.kt +++ b/app/src/main/java/com/example/bluetooth_bike/ui/components/BatteryValuesChart.kt @@ -43,7 +43,7 @@ fun BatteryValuesChart(values: List) { Column( horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.background (MaterialTheme.colorScheme.background) + modifier = Modifier.background(MaterialTheme.colorScheme.background) ) { LineChart(Modifier.size(250.dp, 200.dp), parsedValues) Spacer(modifier = Modifier.height(10.dp)) @@ -116,7 +116,11 @@ fun ShowLegend() { .background(Color.Green, RoundedCornerShape(4.dp)) ) Spacer(modifier = Modifier.width(2.dp)) - Text(text = stringResource(R.string.voltage), fontSize = 6.sp, style = MaterialTheme.typography.titleSmall) + Text( + text = stringResource(R.string.voltage), + fontSize = 6.sp, + style = MaterialTheme.typography.titleSmall + ) Spacer(modifier = Modifier.width(10.dp)) Box( modifier = Modifier @@ -124,7 +128,11 @@ fun ShowLegend() { .background(Color.Yellow, RoundedCornerShape(4.dp)) ) Spacer(modifier = Modifier.width(2.dp)) - Text(text = stringResource(R.string.amperes), fontSize = 6.sp, style = MaterialTheme.typography.titleSmall) + Text( + text = stringResource(R.string.amperes), + fontSize = 6.sp, + style = MaterialTheme.typography.titleSmall + ) Spacer(modifier = Modifier.width(10.dp)) Box( @@ -133,7 +141,11 @@ fun ShowLegend() { .background(Color.Blue, RoundedCornerShape(4.dp)) ) Spacer(modifier = Modifier.width(2.dp)) - Text(text = stringResource(R.string.speed), fontSize = 6.sp, style = MaterialTheme.typography.titleSmall) + Text( + text = stringResource(R.string.speed), + fontSize = 6.sp, + style = MaterialTheme.typography.titleSmall + ) } } @@ -151,16 +163,16 @@ fun Float.mapValueToDifferentRange( fun PreviewBatteryValuesChart() { val values = listOf( - BtMessage("65", "30", "30", "100", "1233", "Ebike01"), - BtMessage("66", "2", "25", "100", "1233", "Ebike01"), - BtMessage("59", "50", "00", "100", "1233", "Ebike01"), - BtMessage("67", "0", "10", "100", "1233", "Ebike01"), - BtMessage("66", "0", "00", "100", "1233", "Ebike01"), - BtMessage("68", "0", "00", "100", "1233", "Ebike01"), - BtMessage("63", "0", "00", "100", "1233", "Ebike01"), - BtMessage("65", "0", "00", "100", "1233", "Ebike01"), + BtMessage("65", "30", "30", "100", "1233"), + BtMessage("66", "2", "25", "100", "1233"), + BtMessage("59", "50", "00", "100", "1233"), + BtMessage("67", "0", "10", "100", "1233"), + BtMessage("66", "0", "00", "100", "1233"), + BtMessage("68", "0", "00", "100", "1233"), + BtMessage("63", "0", "00", "100", "1233"), + BtMessage("65", "0", "00", "100", "1233"), ) - + val uiState = UiState( time = TimeModel("Mon", "12:00", "12 Jan"), values = values ) diff --git a/app/src/main/java/com/example/bluetooth_bike/ui/screens/BikeScreen.kt b/app/src/main/java/com/example/bluetooth_bike/ui/screens/BikeScreen.kt index 4ae61a4..014efe1 100644 --- a/app/src/main/java/com/example/bluetooth_bike/ui/screens/BikeScreen.kt +++ b/app/src/main/java/com/example/bluetooth_bike/ui/screens/BikeScreen.kt @@ -38,8 +38,8 @@ fun BikeScreen( onLightClick: () -> Unit ) { val name = - if (uiState.values.isNotEmpty()) - uiState.values.last().senderName + if (uiState.connectedDevice != null && (uiState.connectedDevice.name?.isNotEmpty()) == true) + uiState.connectedDevice.name else "Unknown" Scaffold( @@ -183,14 +183,14 @@ fun PreviewBikeScreen() { Bluetooth_bikeTheme { val values = listOf( - BtMessage("65", "30", "30", "100", "1233", "Test Ebike"), - BtMessage("66", "2", "25", "100", "1233", "Test Ebike"), - BtMessage("59", "50", "00", "100", "1233", "Test Ebike"), - BtMessage("67", "0", "10", "100", "1233", "Test Ebike"), - BtMessage("66", "0", "00", "100", "1233", "Test Ebike"), - BtMessage("68", "0", "00", "100", "1233", "Test Ebike"), - BtMessage("63", "0", "00", "100", "1233", "Test Ebike"), - BtMessage("65", "0", "00", "100", "1233", "Test Ebike"), + BtMessage("65", "30", "30", "100", "1233"), + BtMessage("66", "2", "25", "100", "1233"), + BtMessage("59", "50", "00", "100", "1233"), + BtMessage("67", "0", "10", "100", "1233"), + BtMessage("66", "0", "00", "100", "1233"), + BtMessage("68", "0", "00", "100", "1233"), + BtMessage("63", "0", "00", "100", "1233"), + BtMessage("65", "0", "00", "100", "1233"), ) BikeScreen( diff --git a/app/src/main/java/com/example/bluetooth_bike/ui/viewmodels/BluetoothViewModel.kt b/app/src/main/java/com/example/bluetooth_bike/ui/viewmodels/BluetoothViewModel.kt index f53763c..a71bb40 100644 --- a/app/src/main/java/com/example/bluetooth_bike/ui/viewmodels/BluetoothViewModel.kt +++ b/app/src/main/java/com/example/bluetooth_bike/ui/viewmodels/BluetoothViewModel.kt @@ -35,6 +35,7 @@ class BluetoothViewModel @Inject constructor( _state ) { devices, isScanning, uiState -> uiState.copy( + connectedDevice = uiState.connectedDevice, pairedDevices = devices, isScanning = isScanning, values = if (uiState.isConnected) uiState.values else emptyList() diff --git a/app/src/test/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapperKtTest.kt b/app/src/test/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapperKtTest.kt index b36f232..ff42724 100644 --- a/app/src/test/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapperKtTest.kt +++ b/app/src/test/java/com/example/bluetooth_bike/data/bluetooth/mappers/BluetoothMessageMapperKtTest.kt @@ -7,14 +7,13 @@ import org.junit.Test class BluetoothMessageTest { @Test fun `test toBluetoothMessage with valid input`() { - val input = "John#12.5$3.2%50&10*33" + val input = "#12.5$3.2%50&10*33" val expected = BtMessage( voltage = "12.5", amperes = "3.2", speed = "50", trip = "10", total = "33", - senderName = "John" ) assertEquals(expected, input.toBtMessage()) } @@ -28,35 +27,32 @@ class BluetoothMessageTest { speed = "", trip = "", total = "", - senderName = "" ) assertEquals(expected, input.toBtMessage()) } @Test fun `test toBluetoothMessage with missing fields`() { - val input = "Jane#12.5$" + val input = "#12.5$" val expected = BtMessage( voltage = "12.5", amperes = "", speed = "", trip = "", total = "", - senderName = "Jane" ) assertEquals(expected, input.toBtMessage()) } @Test fun `test toBluetoothMessage with extra fields`() { - val input = "Mike#12.5$3.2%50&10*extra" + val input = "#12.5$3.2%50&10*extra" val expected = BtMessage( voltage = "12.5", amperes = "3.2", speed = "50", trip = "10", total = "extra", - senderName = "Mike" ) assertEquals(expected, input.toBtMessage()) } diff --git a/app/src/test/java/com/example/bluetooth_bike/ui/MainActivityTest.kt b/app/src/test/java/com/example/bluetooth_bike/ui/MainActivityTest.kt deleted file mode 100644 index cfc5ede..0000000 --- a/app/src/test/java/com/example/bluetooth_bike/ui/MainActivityTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.example.bluetooth_bike.ui - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.junit.Assert.* -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class MainActivityTest \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 322d9a4..a977640 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ buildscript { } // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.2.0" apply false + id("com.android.application") version "8.2.1" apply false id("org.jetbrains.kotlin.android") version "1.8.10" apply false //dagger hilt