fix: properly handle connecting to bonded devices
This commit is contained in:
@@ -59,6 +59,7 @@ dependencies {
|
|||||||
implementation 'androidx.recyclerview:recyclerview:1.2.0'
|
implementation 'androidx.recyclerview:recyclerview:1.2.0'
|
||||||
|
|
||||||
implementation 'com.google.code.gson:gson:2.8.8'
|
implementation 'com.google.code.gson:gson:2.8.8'
|
||||||
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
|
||||||
|
|
||||||
implementation group: 'commons-codec', name: 'commons-codec', version: '1.16.0'
|
implementation group: 'commons-codec', name: 'commons-codec', version: '1.16.0'
|
||||||
|
|
||||||
|
|||||||
@@ -394,9 +394,11 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
|||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun enqueueOperation(operation: BleOperationType) {
|
private fun enqueueOperation(operation: BleOperationType) {
|
||||||
|
/*
|
||||||
if (isScanning) {
|
if (isScanning) {
|
||||||
stopScan()
|
stopScan()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
operationQueue.add(operation)
|
operationQueue.add(operation)
|
||||||
notifyListenersOfQueueChange(operation.device.address)
|
notifyListenersOfQueueChange(operation.device.address)
|
||||||
if (pendingOperation == null) {
|
if (pendingOperation == null) {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ object DecoderIaq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class Measurement (
|
data class Measurement (
|
||||||
|
var deviceId: String? = null,
|
||||||
var msgType: Number? = null,
|
var msgType: Number? = null,
|
||||||
var co2: Number? = null,
|
var co2: Number? = null,
|
||||||
var voc: Number? = null,
|
var voc: Number? = null,
|
||||||
@@ -110,8 +111,5 @@ object DecoderIaq {
|
|||||||
'}'
|
'}'
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toCsv() : String {
|
|
||||||
return "${msgType},${co2},${voc},${humidity},${temperature},${pressure}${pm25},${pm10},${occupancy}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,16 +45,18 @@ class KirbyDevice(
|
|||||||
private val queue: RequestQueue = Volley.newRequestQueue(context)
|
private val queue: RequestQueue = Volley.newRequestQueue(context)
|
||||||
|
|
||||||
fun subscribe() {
|
fun subscribe() {
|
||||||
|
if(statuses.contains(DeviceStatus.CONNECTED)) {
|
||||||
connectionManager.enableNotification(
|
connectionManager.enableNotification(
|
||||||
bleDevice, SERVICE_UUID, CHAR_UUID
|
bleDevice, SERVICE_UUID, CHAR_UUID
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readIaq() {
|
fun readIaq() {
|
||||||
connectionManager.readChar(bleDevice, SERVICE_UUID, CHAR_UUID)
|
connectionManager.readChar(bleDevice, SERVICE_UUID, CHAR_UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onSuccessfulCharRead(
|
override fun onSuccessfulCharRead(
|
||||||
gatt: BluetoothGatt,
|
gatt: BluetoothGatt,
|
||||||
characteristic: BluetoothGattCharacteristic
|
characteristic: BluetoothGattCharacteristic
|
||||||
@@ -66,13 +68,20 @@ class KirbyDevice(
|
|||||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||||
rssi = result.rssi
|
rssi = result.rssi
|
||||||
onStateChange(this)
|
onStateChange(this)
|
||||||
|
|
||||||
|
if(result.isConnectable) {
|
||||||
|
connectionManager.connect(bleDevice)
|
||||||
|
connectionManager.discoverServices(bleDevice)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConnect(gatt: BluetoothGatt) {
|
override fun onConnect(gatt: BluetoothGatt) {
|
||||||
statuses.add(DeviceStatus.CONNECTED)
|
statuses.add(DeviceStatus.CONNECTED)
|
||||||
statuses.remove(DeviceStatus.MISSING)
|
statuses.remove(DeviceStatus.MISSING)
|
||||||
|
|
||||||
|
subscribe()
|
||||||
onStateChange(this)
|
onStateChange(this)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConnectToBondedFailed(gatt: BluetoothGatt) {
|
override fun onConnectToBondedFailed(gatt: BluetoothGatt) {
|
||||||
@@ -136,12 +145,13 @@ class KirbyDevice(
|
|||||||
if (measurement == null) {
|
if (measurement == null) {
|
||||||
payload = Payload(hexPayload)
|
payload = Payload(hexPayload)
|
||||||
} else {
|
} else {
|
||||||
|
measurement.deviceId = bleDevice.address
|
||||||
payload = Payload(measurement.toString())
|
payload = Payload(measurement.toString())
|
||||||
Log.i("BleListener", "Char received: $payload")
|
Log.i("BleListener", "Char received: $payload")
|
||||||
val base64Payload = Base64.getEncoder().encodeToString(characteristic.value)
|
val base64Payload = Base64.getEncoder().encodeToString(characteristic.value)
|
||||||
publishMeasurement(base64Payload)
|
publishMeasurement(base64Payload)
|
||||||
|
|
||||||
loggerDb.writeLog( measurement)
|
loggerDb.writeLog(measurement)
|
||||||
}
|
}
|
||||||
|
|
||||||
measurements.add(payload)
|
measurements.add(payload)
|
||||||
@@ -155,6 +165,11 @@ class KirbyDevice(
|
|||||||
private fun publishMeasurement(payload: String) {
|
private fun publishMeasurement(payload: String) {
|
||||||
val accessKey = BuildConfig.API_KEY
|
val accessKey = BuildConfig.API_KEY
|
||||||
val url = BuildConfig.API_BASE_URL
|
val url = BuildConfig.API_BASE_URL
|
||||||
|
|
||||||
|
if(url.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val eui = "0000${bleDevice.address.replace(":", "")}"
|
val eui = "0000${bleDevice.address.replace(":", "")}"
|
||||||
|
|
||||||
val postData = JSONObject()
|
val postData = JSONObject()
|
||||||
|
|||||||
@@ -15,20 +15,29 @@ import android.content.pm.PackageManager
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View.INVISIBLE
|
import android.view.View.INVISIBLE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||||
import com.logitech.vc.kirbytest.databinding.ActivityMainBinding
|
import com.logitech.vc.kirbytest.databinding.ActivityMainBinding
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
@@ -108,12 +117,33 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setupDevicesList()
|
setupDevicesList()
|
||||||
|
|
||||||
createFileLauncher =
|
createFileLauncher =
|
||||||
registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri: Uri? ->
|
registerForActivityResult(CreateDocument("text/csv")) { uri: Uri? ->
|
||||||
uri?.let {
|
uri?.let {
|
||||||
// Use the URI to write your CSV content
|
// Use the URI to write your CSV content
|
||||||
loggerDb.exportToUri(uri)
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
loggerDb.exportToUri(uri)
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
Toast.makeText(
|
||||||
|
this@MainActivity,
|
||||||
|
"Log export completed.",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
connectionManager.startScan()
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
delay(5000L)
|
||||||
|
connectionManager.stopScan()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleScanning(): Unit {
|
private fun toggleScanning(): Unit {
|
||||||
@@ -156,11 +186,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun addBondedDevices(): Unit {
|
private fun addBondedDevices(): Unit {
|
||||||
bluetoothAdapter.bondedDevices.filter { isKirbyDevice(it) }.forEach {
|
bluetoothAdapter.bondedDevices.filter { isKirbyDevice(it) }.forEach {
|
||||||
val kirbyDevice = newKirbyDevice(it)
|
newKirbyDevice(it)
|
||||||
kirbyDevice.subscribe()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun addDummyDevices() {
|
private fun addDummyDevices() {
|
||||||
for (i in 0..14) {
|
for (i in 0..14) {
|
||||||
@@ -183,7 +213,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||||
if (isKirbyDevice(result.device)) {
|
if (isKirbyDevice(result.device) && result.isConnectable) {
|
||||||
|
|
||||||
Log.i(
|
Log.i(
|
||||||
"ScanCallback",
|
"ScanCallback",
|
||||||
@@ -200,7 +230,10 @@ class MainActivity : AppCompatActivity() {
|
|||||||
return mngr
|
return mngr
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newKirbyDevice(bleDevice: BluetoothDevice): KirbyDevice {
|
private fun newKirbyDevice(
|
||||||
|
bleDevice: BluetoothDevice,
|
||||||
|
autoConnect: Boolean = false
|
||||||
|
): KirbyDevice {
|
||||||
|
|
||||||
val device = KirbyDevice(this.applicationContext, connectionManager, bleDevice, loggerDb) {
|
val device = KirbyDevice(this.applicationContext, connectionManager, bleDevice, loggerDb) {
|
||||||
val i = kirbyDevices.indexOfFirst { d -> d === it }
|
val i = kirbyDevices.indexOfFirst { d -> d === it }
|
||||||
@@ -208,9 +241,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
deviceListAdapter.notifyItemChanged(i)
|
deviceListAdapter.notifyItemChanged(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.i("MainActivity", bleDevice.address)
|
||||||
connectionManager.register(device)
|
connectionManager.register(device)
|
||||||
connectionManager.connect(bleDevice)
|
|
||||||
connectionManager.discoverServices(bleDevice)
|
if (autoConnect) {
|
||||||
|
connectionManager.connect(bleDevice)
|
||||||
|
connectionManager.discoverServices(bleDevice)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
kirbyDevices.add(device)
|
kirbyDevices.add(device)
|
||||||
deviceListAdapter.notifyItemInserted(kirbyDevices.size - 1)
|
deviceListAdapter.notifyItemInserted(kirbyDevices.size - 1)
|
||||||
return device
|
return device
|
||||||
|
|||||||
Reference in New Issue
Block a user