모바일 앱(안드로이드)
BLE 장치와의 UART 통신을 위한 Android 앱 개발
Billcorea
2024. 10. 5. 15:23
반응형
BLE 장치와의 UART 통신을 위한 Android 앱 개발
소개
이번 포스트에서는 no.nordicsemi.android:ble 라이브러리를 사용하여 Android 앱에서 BLE 장치와 UART 통신을 구현하는 방법을 단계별로 설명합니다. BLE 장치와 데이터를 송수신하는 방법을 예제로 보여드리겠습니다.
1. Gradle 설정
먼저, 프로젝트의 build.gradle 파일에 필요한 의존성을 추가합니다:
dependencies {
implementation "no.nordicsemi.android:ble:2.9.0"
implementation "no.nordicsemi.android.support.v18:scanner:1.6.0"
}
2. GATT 서비스 및 특성 UUID 정의
BLE UART 통신을 위해 필요한 GATT 서비스와 특성의 UUID를 정의합니다:
Kotlin
val UART_SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
val CHARACTERISTIC_RX_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
val CHARACTERISTIC_TX_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
3. BLE 장치 검색
BLE 장치를 검색하기 위해 스캐너를 초기화하고 스캔 콜백을 구현합니다:
Kotlin
import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat
import no.nordicsemi.android.support.v18.scanner.ScanCallback
import no.nordicsemi.android.support.v18.scanner.ScanResult
import no.nordicsemi.android.support.v18.scanner.ScanSettings
val scanner = BluetoothLeScannerCompat.getScanner()
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build()
val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
super.onScanResult(callbackType, result)
val device = result.device
val rssi = result.rssi
println("Device found: ${device.address}, RSSI: $rssi")
}
override fun onBatchScanResults(results: List<ScanResult>) {
super.onBatchScanResults(results)
for (result in results) {
val device = result.device
val rssi = result.rssi
println("Device found: ${device.address}, RSSI: $rssi")
}
}
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
println("Scan failed with error code: $errorCode")
}
}
fun startScan() {
val filters = listOf<ScanFilter>() // 필요한 경우 필터 추가
scanner.startScan(filters, settings, scanCallback)
}
fun stopScan() {
scanner.stopScan(scanCallback)
}
4. BLE 매니저 클래스 생성
BLE 매니저 클래스를 생성하여 UART 통신을 관리합니다:
Kotlin
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.content.Context
import no.nordicsemi.android.ble.BleManager
import no.nordicsemi.android.ble.data.Data
class UARTManager(context: Context) : BleManager(context) {
private var txCharacteristic: BluetoothGattCharacteristic? = null
private var rxCharacteristic: BluetoothGattCharacteristic? = null
override fun getGattCallback(): BleManagerGattCallback {
return object : BleManagerGattCallback() {
override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean {
val service = gatt.getService(UART_SERVICE_UUID)
txCharacteristic = service?.getCharacteristic(CHARACTERISTIC_TX_UUID)
rxCharacteristic = service?.getCharacteristic(CHARACTERISTIC_RX_UUID)
return txCharacteristic != null && rxCharacteristic != null
}
override fun initialize() {
setNotificationCallback(rxCharacteristic).with { device, data ->
onDataReceived(device, data)
}
enableNotifications(rxCharacteristic).enqueue()
}
override fun onServicesInvalidated() {
txCharacteristic = null
rxCharacteristic = null
}
}
}
fun send(data: String) {
if (rxCharacteristic == null) return
GlobalScope.launch {
val writeType = if (useLongWrite) {
BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
} else {
BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
}
val request: WriteRequest =
writeCharacteristic(rxCharacteristic, data.toByteArray(), writeType)
if (!useLongWrite) {
request.split()
}
request.suspend()
Log.e("10", "\"$data\" sent")
}
}
private fun onDataReceived(device: BluetoothDevice, data: Data) {
val receivedData = data.getStringValue(0)
println("Received: $receivedData")
}
}
* rxCharacteristic : BLE 기기 입장에서는 수신 이라서 ?
5. Activity에서 BLE 매니저 사용
Activity에서 BLE 매니저를 사용하여 장치에 연결하고 데이터를 송수신합니다:
Kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import no.nordicsemi.android.ble.ktx.state.ConnectionState
import no.nordicsemi.android.ble.ktx.state.stateAsFlow
class MainActivity : AppCompatActivity() {
private lateinit var uartManager: UARTManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
uartManager = UARTManager(this)
// 장치 검색 시작
startScan()
// 장치에 연결
val device: BluetoothDevice = // 연결할 BLE 장치
uartManager.connect(device)
.useAutoConnect(false)
.timeout(10000)
.retry(3, 100)
.enqueue()
// 연결 상태 관찰
lifecycleScope.launch {
uartManager.stateAsFlow().collect { state ->
when (state) {
is ConnectionState.Ready -> {
// 연결 성공
uartManager.send("Hello, UART!")
}
is ConnectionState.Disconnected -> {
// 연결 해제
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
uartManager.disconnect().enqueue()
stopScan()
}
}
결론
이 포스트에서는 no.nordicsemi.android:ble 라이브러리를 사용하여 BLE 장치와 UART 통신을 설정하고 데이터를 송수신하는 방법을 설명했습니다. 또한, BLE 장치를 검색하는 방법도 포함했습니다. BLE 장치와의 통신을 통해 다양한 IoT 애플리케이션을 개발할 수 있습니다. 추가적인 질문이 있거나 더 자세한 설명이 필요하시면 언제든지 댓글로 남겨주세요!
반응형