chore: rename project

This commit is contained in:
Stefan Zollinger
2024-04-10 10:39:07 +02:00
parent c94ca3f40f
commit e53a269b4f
16 changed files with 19 additions and 19 deletions

View File

@@ -0,0 +1,390 @@
package com.logitech.vc.kirbytest
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothDevice.BOND_BONDED
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.le.ScanResult
import android.content.Context
import android.util.Log
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import org.json.JSONException
import org.json.JSONObject
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.Base64
import java.util.EnumSet
import java.util.UUID
import java.util.stream.Collectors
private val SERVICE_UUID = UUID.fromString(BuildConfig.SERVICE_UUID)
private val CHAR_UUID = UUID.fromString(BuildConfig.CHAR_UUID)
enum class DeviceStatus {
CONNECTED, BONDED, SUBSCRIBED, MISSING
}
@SuppressLint("MissingPermission")
class KirbyDevice(
private val context: Context,
private val connectionManager: ConnectionManager,
private val bleDevice: BluetoothDevice,
private val loggerDb: LoggerContract.LoggerDb,
private val onStateChange: (device: KirbyDevice) -> Unit,
) : BleListener(bleDevice.address), DeviceListEntry {
private val queue: RequestQueue = Volley.newRequestQueue(context)
fun subscribe() {
connectionManager.enableNotification(
bleDevice, SERVICE_UUID, CHAR_UUID
)
}
fun readIaq() {
connectionManager.readChar(bleDevice, SERVICE_UUID, CHAR_UUID)
}
override fun onSuccessfulCharRead(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
addMeasurement(characteristic)
onStateChange(this)
}
override fun onScanResult(callbackType: Int, result: ScanResult) {
rssi = result.rssi
onStateChange(this)
}
override fun onConnect(gatt: BluetoothGatt) {
statuses.add(DeviceStatus.CONNECTED)
statuses.remove(DeviceStatus.MISSING)
onStateChange(this)
}
override fun onConnectToBondedFailed(gatt: BluetoothGatt) {
statuses.add(DeviceStatus.MISSING)
onStateChange(this)
}
override fun onDisconnect(gatt: BluetoothGatt) {
statuses.remove(DeviceStatus.CONNECTED)
statuses.remove(DeviceStatus.SUBSCRIBED)
onStateChange(this)
}
override fun onCharChange(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
addMeasurement(characteristic)
onStateChange(this)
}
override fun onSubscribe(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
) {
statuses.add(DeviceStatus.SUBSCRIBED)
onStateChange(this)
}
override fun onUnsubscribe(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor) {
statuses.remove(DeviceStatus.SUBSCRIBED)
onStateChange(this)
}
override fun onQueueSizeChange(groupedOps: Map<String, List<BleOperationType>>) {
hasRunningOp = groupedOps.getOrDefault(bleDevice.address, emptyList()).isNotEmpty()
onStateChange(this)
}
override fun onBonded(device: BluetoothDevice) {
statuses.add(DeviceStatus.BONDED)
onStateChange(this)
}
override fun onUnbonded(device: BluetoothDevice) {
statuses.remove(DeviceStatus.BONDED)
onStateChange(this)
}
override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int) {
this.rssi = rssi
onStateChange(this)
}
override var hasRunningOp: Boolean = false
override var rssi: Int? = null
private fun addMeasurement(characteristic: BluetoothGattCharacteristic) {
val hexPayload = characteristic.value.toHexString().substring(2)
val measurement = DecoderIaq.parseMeasurement(hexPayload)
var payload : Payload
if (measurement == null) {
payload = Payload(hexPayload)
} else {
payload = Payload(measurement.toString())
Log.i("BleListener", "Char received: $payload")
val base64Payload = Base64.getEncoder().encodeToString(characteristic.value)
publishMeasurement(base64Payload)
loggerDb.writeLog( measurement)
}
measurements.add(payload)
if (measurements.size > maxMeasurements) {
measurements.removeFirst()
}
}
private fun publishMeasurement(payload: String) {
val accessKey = BuildConfig.API_KEY
val url = BuildConfig.API_BASE_URL
val eui = "0000${bleDevice.address.replace(":", "")}"
val postData = JSONObject()
try {
Log.i("POST", "Transmitting for $eui: $payload")
postData.put("accessKey", accessKey)
postData.put("metricPayload", payload)
postData.put("eui", eui)
} catch (e: JSONException) {
e.printStackTrace()
}
val request = JsonObjectRequest(
Request.Method.POST, url, postData,
{ response ->
Log.i("sendDataResponse", "Response is: $response")
}
) { error -> error.printStackTrace() }
queue.add(request)
}
private val measurements = ArrayList<Payload>()
private val maxMeasurements = 20
private val statuses = EnumSet.noneOf(DeviceStatus::class.java)
init {
if (bleDevice.bondState == BOND_BONDED) {
statuses.add(DeviceStatus.BONDED)
}
}
override val address: String
get() = bleDevice.address
override val name: String?
get() = bleDevice.name
override val status: String?
get() = statuses.stream().map { it.name }.collect(Collectors.joining(", "))
override fun getMeasurements(): List<Measurement> {
val result = mutableListOf<Measurement>()
measurements.reversed().forEach { m -> result.addAll(payloadToMeasurements(m))}
/*
var pl = Payload(payload = "006b04ab74a1ed0d101404", ts = "2000")
result.addAll(payloadToMeasurements(pl))
result.addAll(payloadToMeasurements(pl))
*/
return result
}
override fun getActions(): List<Action> {
val actions = mutableListOf<Action>()
if (!statuses.contains(DeviceStatus.BONDED)) {
actions.add(object : Action {
override fun getLabel(): String {
return "Bond"
}
override fun getIcon(): Int {
return R.drawable.action_icon_bond
}
override fun execute() {
connectionManager.bond(bleDevice)
}
})
}
if (!statuses.contains(DeviceStatus.CONNECTED)
) {
actions.add(object : Action {
override fun getLabel(): String {
return "Connect"
}
override fun getIcon(): Int {
return R.drawable.action_icon_connect
}
override fun execute() {
connectionManager.connect(bleDevice)
connectionManager.readRemoteRssi(bleDevice)
connectionManager.discoverServices(bleDevice)
}
})
}
if (statuses.contains(DeviceStatus.CONNECTED)) {
actions.add(object : Action {
override fun getLabel(): String {
return "Disconnect"
}
override fun getIcon(): Int {
return R.drawable.action_icon_disconnect
}
override fun execute() {
connectionManager.teardownConnection(bleDevice)
}
})
actions.add(object : Action {
override fun getLabel(): String {
return "Fetch Measurement"
}
override fun getIcon(): Int {
return R.drawable.action_icon_fetch_measurement
}
override fun execute() {
readIaq()
}
})
if (!statuses.contains(DeviceStatus.SUBSCRIBED)) {
actions.add(object : Action {
override fun getLabel(): String {
return "Subscribe"
}
override fun getIcon(): Int {
return R.drawable.action_icon_subscribe
}
override fun execute() {
subscribe()
}
})
}
actions.add(object : Action {
override fun getLabel(): String {
return "Update Signal Strength"
}
override fun getIcon(): Int {
return R.drawable.action_icon_update_signal_strength
}
override fun execute() {
connectionManager.readRemoteRssi(bleDevice)
}
})
}
if (statuses.contains(DeviceStatus.SUBSCRIBED)) {
actions.add(object : Action {
override fun getLabel(): String {
return "Unsubscribe"
}
override fun getIcon(): Int {
return R.drawable.action_icon_subscribe_disable
}
override fun execute() {
connectionManager.disableNotification(
bleDevice, SERVICE_UUID, CHAR_UUID
)
}
})
}
if (statuses.contains(DeviceStatus.BONDED)
) {
actions.add(object : Action {
override fun getLabel(): String {
return "Unbond"
}
override fun getIcon(): Int {
return R.drawable.action_icon_unbond
}
override fun execute() {
connectionManager.unbond(bleDevice)
}
})
}
return actions;
}
}
data class Payload(
val payload: String,
val ts: String = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("dd.MM.yy HH:mm:ss"))
)
fun bytesToUInt16(arr: ByteArray, start: Int): Int {
return ByteBuffer.wrap(arr, start, 2)
.order(ByteOrder.LITTLE_ENDIAN).short.toInt() and 0xFFFF
}
fun bytesToInt16(arr: ByteArray, start: Int): Short {
return ByteBuffer.wrap(arr, start, 2)
.order(ByteOrder.LITTLE_ENDIAN).short
}
fun bytesToInt32(arr: ByteArray, start: Int): Int {
return ByteBuffer.wrap(arr, start, 4)
.order(ByteOrder.LITTLE_ENDIAN).int
}
private fun payloadToMeasurements(payload: Payload): List<Measurement> {
return listOf(object : Measurement {
override fun getLabel(): String {
return payload.ts.toString()
}
override fun getFormattedValue(): String {
return payload.payload
}
override fun getIcon(): Int? {
return R.drawable.baseline_numbers_24
}
}
)
}