[O] Add proper observe function
This commit is contained in:
@@ -7,7 +7,6 @@ import android.os.Looper
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.welie.blessed.BluetoothPeripheral
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.hydev.wearsync.bles.BluetoothHandler.Companion.ble
|
import org.hydev.wearsync.bles.BluetoothHandler.Companion.ble
|
||||||
import org.hydev.wearsync.databinding.ActivityScanBinding
|
import org.hydev.wearsync.databinding.ActivityScanBinding
|
||||||
@@ -41,7 +40,7 @@ class ActivityScan : AppCompatActivity() {
|
|||||||
val pairedAddresses = pairedDevices.map { it.address }.toSet()
|
val pairedAddresses = pairedDevices.map { it.address }.toSet()
|
||||||
|
|
||||||
// Scan devices
|
// Scan devices
|
||||||
val scannedDevices = ArrayList<BluetoothPeripheral>()
|
val scannedDevices = ArrayList<BluePeri>()
|
||||||
ble.central.scanForPeripherals({ peripheral, scanResult ->
|
ble.central.scanForPeripherals({ peripheral, scanResult ->
|
||||||
if (peripheral.name.isBlank() || scannedDevices.contains(peripheral)) return@scanForPeripherals
|
if (peripheral.name.isBlank() || scannedDevices.contains(peripheral)) return@scanForPeripherals
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import com.influxdb.client.domain.WritePrecision
|
import com.influxdb.client.domain.WritePrecision
|
||||||
import com.influxdb.client.kotlin.InfluxDBClientKotlin
|
import com.influxdb.client.kotlin.InfluxDBClientKotlin
|
||||||
import com.influxdb.client.kotlin.InfluxDBClientKotlinFactory
|
import com.influxdb.client.kotlin.InfluxDBClientKotlinFactory
|
||||||
|
import com.welie.blessed.BluetoothPeripheral
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
|
|
||||||
@@ -25,10 +26,10 @@ fun View.snack(msg: String) = Snackbar.make(this, msg, Snackbar.LENGTH_LONG)
|
|||||||
.setAction("Action", null).show()
|
.setAction("Action", null).show()
|
||||||
|
|
||||||
inline fun <reified T> Context.getSysServ() = getSystemService(T::class.java) as T
|
inline fun <reified T> Context.getSysServ() = getSystemService(T::class.java) as T
|
||||||
|
typealias BluePeri = BluetoothPeripheral
|
||||||
fun Context.blueMan() = getSysServ<BluetoothManager>()
|
fun Context.blueMan() = getSysServ<BluetoothManager>()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface Prefs {
|
interface Prefs {
|
||||||
var chosenDevice: String?
|
var chosenDevice: String?
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.welie.blessed.*
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
|
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
|
||||||
|
import org.hydev.wearsync.BluePeri
|
||||||
import org.hydev.wearsync.bles.decoders.*
|
import org.hydev.wearsync.bles.decoders.*
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import timber.log.Timber.DebugTree
|
import timber.log.Timber.DebugTree
|
||||||
@@ -14,7 +15,7 @@ import java.util.*
|
|||||||
internal class BluetoothHandler private constructor(context: Context) {
|
internal class BluetoothHandler private constructor(context: Context) {
|
||||||
var central: BluetoothCentralManager
|
var central: BluetoothCentralManager
|
||||||
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
val batteryChannel = Channel<BatteryMeasurement>(UNLIMITED)
|
val batteryChannel = Channel<BatteryMeasurement>(UNLIMITED)
|
||||||
val heartRateChannel = Channel<HeartRateMeasurement>(UNLIMITED)
|
val heartRateChannel = Channel<HeartRateMeasurement>(UNLIMITED)
|
||||||
val bloodPressureChannel = Channel<BloodPressureMeasurement>(UNLIMITED)
|
val bloodPressureChannel = Channel<BloodPressureMeasurement>(UNLIMITED)
|
||||||
@@ -24,7 +25,7 @@ internal class BluetoothHandler private constructor(context: Context) {
|
|||||||
val temperatureChannel = Channel<TemperatureMeasurement>(UNLIMITED)
|
val temperatureChannel = Channel<TemperatureMeasurement>(UNLIMITED)
|
||||||
val weightChannel = Channel<WeightMeasurement>(UNLIMITED)
|
val weightChannel = Channel<WeightMeasurement>(UNLIMITED)
|
||||||
|
|
||||||
private fun handlePeripheral(peripheral: BluetoothPeripheral) {
|
private fun handlePeripheral(peripheral: BluePeri) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
try {
|
try {
|
||||||
Timber.i("MTU is ${peripheral.requestMtu(185)}")
|
Timber.i("MTU is ${peripheral.requestMtu(185)}")
|
||||||
@@ -34,13 +35,13 @@ internal class BluetoothHandler private constructor(context: Context) {
|
|||||||
Timber.i("Received: ${peripheral.read(ModelDecoder())}")
|
Timber.i("Received: ${peripheral.read(ModelDecoder())}")
|
||||||
Timber.i("Battery level: ${peripheral.read(BatteryDecoder())}")
|
Timber.i("Battery level: ${peripheral.read(BatteryDecoder())}")
|
||||||
|
|
||||||
peripheral.setupNotification(batteryChannel, BatteryDecoder())
|
peripheral.observe(batteryChannel, BatteryDecoder())
|
||||||
peripheral.setupNotification(heartRateChannel, HeartRateDecoder())
|
peripheral.observe(heartRateChannel, HeartRateDecoder())
|
||||||
peripheral.setupNotification(temperatureChannel, TemperatureDecoder())
|
peripheral.observe(temperatureChannel, TemperatureDecoder())
|
||||||
peripheral.setupNotification(weightChannel, WeightDecoder())
|
peripheral.observe(weightChannel, WeightDecoder())
|
||||||
peripheral.setupNotification(bloodPressureChannel, BloodPressureDecoder())
|
peripheral.observe(bloodPressureChannel, BloodPressureDecoder())
|
||||||
peripheral.setupNotification(pulseOxSpotChannel, PLXSpotDecoder())
|
peripheral.observe(pulseOxSpotChannel, PLXSpotDecoder())
|
||||||
peripheral.setupNotification(pulseOxContinuousChannel, PLXContinuousDecoder())
|
peripheral.observe(pulseOxContinuousChannel, PLXContinuousDecoder())
|
||||||
setupGLXnotifications(peripheral)
|
setupGLXnotifications(peripheral)
|
||||||
|
|
||||||
peripheral.getCharacteristic(CONTOUR_SERVICE_UUID, CONTOUR_CLOCK)?.let {
|
peripheral.getCharacteristic(CONTOUR_SERVICE_UUID, CONTOUR_CLOCK)?.let {
|
||||||
@@ -54,7 +55,7 @@ internal class BluetoothHandler private constructor(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun writeContourClock(peripheral: BluetoothPeripheral) {
|
private suspend fun writeContourClock(peripheral: BluePeri) {
|
||||||
val calendar = Calendar.getInstance()
|
val calendar = Calendar.getInstance()
|
||||||
val offsetInMinutes = calendar.timeZone.rawOffset / 60000
|
val offsetInMinutes = calendar.timeZone.rawOffset / 60000
|
||||||
calendar.timeZone = TimeZone.getTimeZone("UTC")
|
calendar.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
@@ -70,8 +71,8 @@ internal class BluetoothHandler private constructor(context: Context) {
|
|||||||
peripheral.writeCharacteristic(CONTOUR_SERVICE_UUID, CONTOUR_CLOCK, parser.value, WriteType.WITH_RESPONSE)
|
peripheral.writeCharacteristic(CONTOUR_SERVICE_UUID, CONTOUR_CLOCK, parser.value, WriteType.WITH_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun setupGLXnotifications(peripheral: BluetoothPeripheral) {
|
private suspend fun setupGLXnotifications(peripheral: BluePeri) {
|
||||||
peripheral.setupNotification(glucoseChannel, GlucoseDecoder())
|
peripheral.observe(glucoseChannel, GlucoseDecoder())
|
||||||
|
|
||||||
peripheral.getCharacteristic(GLUCOSE_SERVICE_UUID, GLUCOSE_RECORD_ACCESS_POINT_CHARACTERISTIC_UUID)?.let {
|
peripheral.getCharacteristic(GLUCOSE_SERVICE_UUID, GLUCOSE_RECORD_ACCESS_POINT_CHARACTERISTIC_UUID)?.let {
|
||||||
val result = peripheral.observe(it) { value ->
|
val result = peripheral.observe(it) { value ->
|
||||||
@@ -84,28 +85,33 @@ internal class BluetoothHandler private constructor(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun writeGetAllGlucoseMeasurements(peripheral: BluetoothPeripheral) {
|
private suspend fun writeGetAllGlucoseMeasurements(peripheral: BluePeri) {
|
||||||
val OP_CODE_REPORT_STORED_RECORDS: Byte = 1
|
val OP_CODE_REPORT_STORED_RECORDS: Byte = 1
|
||||||
val OPERATOR_ALL_RECORDS: Byte = 1
|
val OPERATOR_ALL_RECORDS: Byte = 1
|
||||||
val command = byteArrayOf(OP_CODE_REPORT_STORED_RECORDS, OPERATOR_ALL_RECORDS)
|
val command = byteArrayOf(OP_CODE_REPORT_STORED_RECORDS, OPERATOR_ALL_RECORDS)
|
||||||
peripheral.writeCharacteristic(GLUCOSE_SERVICE_UUID, GLUCOSE_RECORD_ACCESS_POINT_CHARACTERISTIC_UUID, command, WriteType.WITH_RESPONSE)
|
peripheral.writeCharacteristic(GLUCOSE_SERVICE_UUID, GLUCOSE_RECORD_ACCESS_POINT_CHARACTERISTIC_UUID, command, WriteType.WITH_RESPONSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T> BluetoothPeripheral.setupNotification(channel: Channel<T>, dec: IDecoder<T>)
|
/**
|
||||||
{
|
* Observe a specific mesasurement
|
||||||
|
*/
|
||||||
|
suspend fun <T> BluePeri.observe(dec: IDecoder<T>, callback: (T) -> Unit) {
|
||||||
getCharacteristic(dec.sid, dec.cid)?.let {
|
getCharacteristic(dec.sid, dec.cid)?.let {
|
||||||
observe(it) { value ->
|
observe(it) { value ->
|
||||||
val measurement = dec.decode(value)
|
val measurement = dec.decode(value)
|
||||||
channel.trySend(measurement)
|
callback(measurement)
|
||||||
Timber.d(measurement.toString())
|
Timber.d(measurement.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun <T> BluePeri.observe(chan: Channel<T>, dec: IDecoder<T>) =
|
||||||
|
observe(dec) { chan.trySend(it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan and connect to a peripheral at a specific address
|
* Scan and connect to a peripheral at a specific address
|
||||||
*/
|
*/
|
||||||
fun connectAddress(address: String, callback: (BluetoothPeripheral) -> Unit = {}) {
|
fun connectAddress(address: String, callback: (BluePeri) -> Unit = {}) {
|
||||||
central.stopScan()
|
central.stopScan()
|
||||||
central.scanForPeripheralsWithAddresses(arrayOf(address), { peripheral, scanResult ->
|
central.scanForPeripheralsWithAddresses(arrayOf(address), { peripheral, scanResult ->
|
||||||
if (peripheral.address != address) return@scanForPeripheralsWithAddresses
|
if (peripheral.address != address) return@scanForPeripheralsWithAddresses
|
||||||
@@ -115,10 +121,8 @@ internal class BluetoothHandler private constructor(context: Context) {
|
|||||||
}, {})
|
}, {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun connectPeripheral(peripheral: BluetoothPeripheral, callback: () -> Unit = {}) {
|
fun connectPeripheral(peripheral: BluePeri, callback: () -> Unit = {}) {
|
||||||
peripheral.observeBondState {
|
peripheral.observeBondState { Timber.i("Bond state is $it") }
|
||||||
Timber.i("Bond state is $it")
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
try {
|
try {
|
||||||
@@ -146,7 +150,7 @@ internal class BluetoothHandler private constructor(context: Context) {
|
|||||||
return instance!!
|
return instance!!
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun <T> BluetoothPeripheral.read(decoder: IDecoder<T>) =
|
suspend fun <T> BluePeri.read(decoder: IDecoder<T>) =
|
||||||
getCharacteristic(decoder.sid, decoder.cid)?.let { decoder.decode(readCharacteristic(it)) }
|
getCharacteristic(decoder.sid, decoder.cid)?.let { decoder.decode(readCharacteristic(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user