diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..1d40cc9
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+BMSMonitor
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 61a9130..fb7f4a8 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 9d38be2..56d6814 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -4,7 +4,7 @@
-
-
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..7e340a7
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 19aa6a5..26fb6d1 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,5 @@
-
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 15b7d72..ab2c10d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,7 +7,6 @@ plugins {
android {
compileSdkVersion 29
- buildToolsVersion "30.0.2"
defaultConfig {
applicationId "de.jnns.bmsmonitor"
@@ -38,6 +37,7 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
+ namespace 'de.jnns.bmsmonitor'
}
dependencies {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a0bd31e..2de5da5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/app/src/main/java/de/jnns/bmsmonitor/BatteryFragment.kt b/app/src/main/java/de/jnns/bmsmonitor/BatteryFragment.kt
index eda9f35..5e397c6 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/BatteryFragment.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/BatteryFragment.kt
@@ -50,9 +50,6 @@ class BatteryFragment : Fragment() {
override fun onReceive(context: Context, intent: Intent) {
try {
val msg: String = intent.getStringExtra("batteryData")!!
-
- binding.labelStatus.text = String.format(resources.getString(R.string.connectedToBms), intent.getStringExtra("deviceName"))
-
if (msg.isNotEmpty()) {
updateUi(Gson().fromJson(msg, BatteryData::class.java))
}
@@ -98,31 +95,58 @@ class BatteryFragment : Fragment() {
minCellVoltage = PreferenceManager.getDefaultSharedPreferences(requireContext()).getString("minCellVoltage", "2500")!!.toInt()
maxCellVoltage = PreferenceManager.getDefaultSharedPreferences(requireContext()).getString("maxCellVoltage", "4200")!!.toInt()
- binding.barchartCells.setNoDataTextColor(requireActivity().getColor(R.color.white))
- binding.barchartCells.setNoDataText("...")
+ binding.barchartCells1.setNoDataTextColor(requireActivity().getColor(R.color.white))
+ binding.barchartCells1.setNoDataText("...")
+
+ binding.barchartCells1.setPinchZoom(false)
+ binding.barchartCells1.setTouchEnabled(false)
+ binding.barchartCells1.isClickable = false
+ binding.barchartCells1.isDoubleTapToZoomEnabled = false
+
+ binding.barchartCells1.setDrawBorders(false)
+ binding.barchartCells1.setDrawValueAboveBar(true)
+ binding.barchartCells1.setDrawBorders(false)
+ binding.barchartCells1.setDrawGridBackground(false)
+
+ binding.barchartCells1.description.isEnabled = false
+ binding.barchartCells1.legend.isEnabled = false
+
+ binding.barchartCells1.axisLeft.setDrawGridLines(false)
+ binding.barchartCells1.axisLeft.setDrawLabels(false)
+ binding.barchartCells1.axisLeft.setDrawAxisLine(false)
+
+ binding.barchartCells1.xAxis.setDrawGridLines(false)
+ binding.barchartCells1.xAxis.setDrawLabels(false)
+ binding.barchartCells1.xAxis.setDrawAxisLine(false)
+
+ binding.barchartCells1.axisRight.isEnabled = false
+
- binding.barchartCells.setPinchZoom(false)
- binding.barchartCells.setTouchEnabled(false)
- binding.barchartCells.isClickable = false
- binding.barchartCells.isDoubleTapToZoomEnabled = false
+ binding.barchartCells2.setNoDataTextColor(requireActivity().getColor(R.color.white))
+ binding.barchartCells2.setNoDataText("...")
- binding.barchartCells.setDrawBorders(false)
- binding.barchartCells.setDrawValueAboveBar(true)
- binding.barchartCells.setDrawBorders(false)
- binding.barchartCells.setDrawGridBackground(false)
+ binding.barchartCells2.setPinchZoom(false)
+ binding.barchartCells2.setTouchEnabled(false)
+ binding.barchartCells2.isClickable = false
+ binding.barchartCells2.isDoubleTapToZoomEnabled = false
- binding.barchartCells.description.isEnabled = false
- binding.barchartCells.legend.isEnabled = false
+ binding.barchartCells2.setDrawBorders(false)
+ binding.barchartCells2.setDrawValueAboveBar(true)
+ binding.barchartCells2.setDrawBorders(false)
+ binding.barchartCells2.setDrawGridBackground(false)
- binding.barchartCells.axisLeft.setDrawGridLines(false)
- binding.barchartCells.axisLeft.setDrawLabels(false)
- binding.barchartCells.axisLeft.setDrawAxisLine(false)
+ binding.barchartCells2.description.isEnabled = false
+ binding.barchartCells2.legend.isEnabled = false
- binding.barchartCells.xAxis.setDrawGridLines(false)
- binding.barchartCells.xAxis.setDrawLabels(false)
- binding.barchartCells.xAxis.setDrawAxisLine(false)
+ binding.barchartCells2.axisLeft.setDrawGridLines(false)
+ binding.barchartCells2.axisLeft.setDrawLabels(false)
+ binding.barchartCells2.axisLeft.setDrawAxisLine(false)
- binding.barchartCells.axisRight.isEnabled = false
+ binding.barchartCells2.xAxis.setDrawGridLines(false)
+ binding.barchartCells2.xAxis.setDrawLabels(false)
+ binding.barchartCells2.xAxis.setDrawAxisLine(false)
+
+ binding.barchartCells2.axisRight.isEnabled = false
}
override fun onResume() {
@@ -145,84 +169,89 @@ class BatteryFragment : Fragment() {
}
requireActivity().runOnUiThread {
+ binding.labelStatus.text = String.format(resources.getString(R.string.connectedToBms), batteryData.bpVersion, batteryData.bpNumber)
+
// Power Gauge
- val powerUsage = batteryData.power * -1.0f
+ val powerUsage = batteryData.packCurrent * batteryData.packVoltage
- binding.speedViewSpeed.speedTo(powerUsage, 1000)
+ var chargePower:Float = 0.0f
- if (powerUsage < 0.0f) {
- binding.labelPower.text = "+${powerUsage.roundToInt() * -1}"
+ if(batteryData.packCurrent >= 0.0f)
+ {
+ chargePower = batteryData.packCurrent / batteryData.maxChargeCurrent
+ chargePower = chargePower * -500
} else {
- binding.labelPower.text = powerUsage.roundToInt().toString()
- }
-
- // Remaining Time
- wattValues[smoothIndex] = batteryData.power
- ++smoothIndex
-
- if (smoothIndex == smoothCount) {
- smoothIndex = 0
+ chargePower = batteryData.packCurrent / batteryData.maxDischargeCurrent
+ chargePower = chargePower * -1000
}
- var averagePower = wattValues.filter { x -> x != 0.0f }.average().toFloat()
+ binding.speedViewSpeed.speedTo(chargePower, 1000)
- if (averagePower < 0.0f) {
- averagePower *= -1
- }
-
- val wattSeconds: Float = when {
- batteryData.power < 0.0f -> {
- (batteryData.watthours / averagePower) * 3600
- }
- batteryData.power > 0.0f -> {
- ((batteryData.totalWatthours - batteryData.watthours) / averagePower) * 3600
- }
- else -> {
- 0.0f
- }
- }
-
- if (batteryData.power == 0.0f) {
- wattValues.fill(0.0f)
+ if (powerUsage < 0.0f) {
+ binding.labelPower.text = "+${powerUsage.roundToInt() * -1}"
+ } else {
+ binding.labelPower.text = powerUsage.roundToInt().toString()
}
- val remainingMinutes = (wattSeconds % 3600) / 60
- val remainingHours = (wattSeconds - remainingMinutes) / 3600
-
- binding.labelTime.text = String.format("%02d:%02d", remainingHours.roundToInt(), remainingMinutes.roundToInt())
+ binding.labelCycle.text = String.format("Cycle:%s", batteryData.packDischargCycle.toString())
// Cell Bar-Diagram
val cellBars = ArrayList()
-
- for ((i, cell) in batteryData.cellVoltages.withIndex()) {
- cellBars.add(BarEntry(i.toFloat(), cell))
- }
+ cellBars.add(BarEntry(0.toFloat(), batteryData.cellVoltage1))
+ cellBars.add(BarEntry(1.toFloat(), batteryData.cellVoltage2))
+ cellBars.add(BarEntry(2.toFloat(), batteryData.cellVoltage3))
+ cellBars.add(BarEntry(3.toFloat(), batteryData.cellVoltage4))
+ cellBars.add(BarEntry(4.toFloat(), batteryData.cellVoltage5))
+ cellBars.add(BarEntry(5.toFloat(), batteryData.cellVoltage6))
+ cellBars.add(BarEntry(6.toFloat(), batteryData.cellVoltage7))
+ cellBars.add(BarEntry(7.toFloat(), batteryData.cellVoltage8))
val barDataSetVoltage = BarDataSet(cellBars, "Cell Voltages")
barDataSetVoltage.valueTextColor = requireActivity().getColor(R.color.white)
barDataSetVoltage.valueTextSize = 12.0f
- barDataSetVoltage.valueFormatter = DefaultValueFormatter(2)
+ barDataSetVoltage.valueFormatter = DefaultValueFormatter(3)
barDataSetVoltage.setColors(requireActivity().getColor(R.color.primary))
val barData = BarData(barDataSetVoltage)
- binding.barchartCells.data = barData
- binding.barchartCells.invalidate()
-
- // Row 1
- val totalPercentage = ((batteryData.percentage) * 1000.0f).roundToInt() / 10.0f
+ binding.barchartCells1.data = barData
+ binding.barchartCells1.invalidate()
+
+ val cellBars1 = ArrayList()
+
+ cellBars1.add(BarEntry(8.toFloat(), batteryData.cellVoltage9))
+ cellBars1.add(BarEntry(9.toFloat(), batteryData.cellVoltage10))
+ cellBars1.add(BarEntry(10.toFloat(), batteryData.cellVoltage11))
+ cellBars1.add(BarEntry(11.toFloat(), batteryData.cellVoltage12))
+ cellBars1.add(BarEntry(12.toFloat(), batteryData.cellVoltage13))
+ cellBars1.add(BarEntry(13.toFloat(), batteryData.cellVoltage14))
+ cellBars1.add(BarEntry(14.toFloat(), batteryData.cellVoltage15))
+ cellBars1.add(BarEntry(15.toFloat(), batteryData.cellVoltage16))
+
+ val barDataSetVoltage1 = BarDataSet(cellBars, "Cell Voltages")
+ barDataSetVoltage1.valueTextColor = requireActivity().getColor(R.color.white)
+ barDataSetVoltage1.valueTextSize = 12.0f
+ barDataSetVoltage1.valueFormatter = DefaultValueFormatter(3)
+ barDataSetVoltage1.setColors(requireActivity().getColor(R.color.primary))
+
+ val barData1 = BarData(barDataSetVoltage)
+ binding.barchartCells2.data = barData1
+ binding.barchartCells2.invalidate()
+
+ var totalPercentage = batteryData.packRSOC.toUByte()
+ if(totalPercentage > 100U) {
+ totalPercentage = 100U
+ }
- binding.labelVoltage.text = roundTo(batteryData.voltage, 1).toString()
+ binding.labelVoltage.text = roundTo(batteryData.packVoltage, 1).toString()
binding.labelPercentage.text = totalPercentage.toString()
- uiBatteryCapacityBar(totalPercentage)
+ uiBatteryCapacityBar(totalPercentage.toFloat())
- // Row 2
- binding.labelCurrent.text = String.format(Locale.US, "%.1f", roundTo(batteryData.current, 1))
- binding.labelCapacityWh.text = batteryData.watthours.roundToInt().toString()
+ binding.labelCurrent.text = roundTo(batteryData.packCurrent, 1).toString()
+ binding.labelCapacityWh.text = roundTo(batteryData.capacity, 1).toString()
- // Row 3
- binding.labelTemperature.text = roundTo(batteryData.avgTemperature, 1).toString()
- binding.labelTemperatureMax.text = roundTo(batteryData.maxTemperature, 1).toString()
+ binding.labelTemperature.text = roundTo(batteryData.sysTemperature, 1).toString()
+ binding.labelTemperatureMax.text = roundTo(batteryData.heatsinkTemperature, 1).toString()
}
}
diff --git a/app/src/main/java/de/jnns/bmsmonitor/MainActivity.kt b/app/src/main/java/de/jnns/bmsmonitor/MainActivity.kt
index f84ae65..b440db9 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/MainActivity.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/MainActivity.kt
@@ -2,14 +2,18 @@ package de.jnns.bmsmonitor
import android.Manifest
import android.content.Intent
+import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.os.Bundle
+import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.navigation.findNavController
import androidx.preference.PreferenceManager
import de.jnns.bmsmonitor.bluetooth.BleService
import de.jnns.bmsmonitor.databinding.ActivityMainBinding
+//import de.jnns.bmsmonitor.BatteryFragment1
+import de.jnns.bmsmonitor.BatteryFragment
import de.jnns.bmsmonitor.services.BikeService
import de.jnns.bmsmonitor.services.BmsService
import io.realm.Realm
@@ -22,7 +26,7 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-
+ Log.d("BMS", "MainActivity Start...")
Realm.init(this)
Realm.compactRealm(Realm.getDefaultConfiguration()!!)
@@ -33,7 +37,8 @@ class MainActivity : AppCompatActivity() {
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
- val batteryEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("batteryEnabled", false)
+// val batteryEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("batteryEnabled", false)
+ val batteryEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("batteryEnabled", true)
val bikeEnabled = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("bikeEnabled", false)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
@@ -77,6 +82,7 @@ class MainActivity : AppCompatActivity() {
when (requestCode) {
4711 -> {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
+ Intent(this, BleService::class.java).also { intent -> startService(intent) }
Intent(this, BmsService::class.java).also { intent ->
startService(intent)
}
diff --git a/app/src/main/java/de/jnns/bmsmonitor/SettingsFragment.kt b/app/src/main/java/de/jnns/bmsmonitor/SettingsFragment.kt
index f4f30cd..5a8a515 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/SettingsFragment.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/SettingsFragment.kt
@@ -17,16 +17,16 @@ class SettingsFragment : PreferenceFragmentCompat() {
super.onViewCreated(view, savedInstanceState)
val btPreference = findPreference("macAddress") as ListPreference
- val btPreferenceBike = findPreference("macAddressBike") as ListPreference
+// val btPreferenceBike = findPreference("macAddressBike") as ListPreference
val bleNames = BleManager.i.getBleNames()
bleNames.add("None")
btPreference.entries = bleNames.toTypedArray()
- btPreferenceBike.entries = bleNames.toTypedArray()
+// btPreferenceBike.entries = bleNames.toTypedArray()
val bleAddresses = BleManager.i.getBleAddresses()
bleAddresses.add("0")
btPreference.entryValues = bleAddresses.toTypedArray()
- btPreferenceBike.entryValues = bleAddresses.toTypedArray()
+// btPreferenceBike.entryValues = bleAddresses.toTypedArray()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BikeGattClientCallback.kt b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BikeGattClientCallback.kt
index 80bdb94..3053234 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BikeGattClientCallback.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BikeGattClientCallback.kt
@@ -69,13 +69,9 @@ class BikeGattClientCallback(
super.onCharacteristicChanged(gatt, characteristic)
if (characteristic.uuid == lcdToMcuUuid) {
- // Log.d("BluetoothGatt", "FrameData (LCD): " + characteristic.value.toHexString())
-
val data = LcdToMcuResponse(characteristic.value)
onLcdToMcuDataAvailable(data)
} else if (characteristic.uuid == mcuToLcdUuid) {
- // Log.d("BluetoothGatt", "FrameData (MCU): " + characteristic.value.toHexString())
-
val data = McuToLcdResponse(characteristic.value)
onMcuToLcdDataAvailable(data)
}
diff --git a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleManager.kt b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleManager.kt
index 1539980..cebd823 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleManager.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleManager.kt
@@ -1,6 +1,7 @@
package de.jnns.bmsmonitor.bluetooth
import android.bluetooth.BluetoothDevice
+import android.util.Log
import kotlinx.coroutines.Runnable
class BleManager {
diff --git a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleService.kt b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleService.kt
index 007c334..aebaba3 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleService.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BleService.kt
@@ -2,27 +2,91 @@ package de.jnns.bmsmonitor.bluetooth
import android.app.Service
import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothGatt
+import android.bluetooth.BluetoothGatt.GATT_SUCCESS
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor
+import android.bluetooth.BluetoothGattServer
+import android.bluetooth.BluetoothGattServerCallback
+import android.bluetooth.BluetoothGattService
+import android.bluetooth.BluetoothManager
+import android.bluetooth.BluetoothProfile
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
+import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.os.Handler
import android.os.IBinder
+import android.util.Log
+import de.jnns.bmsmonitor.R
+import java.util.*
@ExperimentalUnsignedTypes
class BleService : Service() {
+ private var TAG: String = "BMS"
// bluetooth stuff
private var isScanning = false
private lateinit var bluetoothLeScanner: BluetoothLeScanner
+ private lateinit var mBluetoothManager: BluetoothManager
+ private lateinit var mGattServer: BluetoothGattServer
+// UUID128(uuid_service_wireless_uart, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x00, 0x01, 0xFF, 0x01)
+// "01FF0100-BA5E-F4EE-5CA1-EB1E5E4B1CE0"
+// UUID128(uuid_uart_stream, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x01, 0x01, 0xFF, 0x01)
+// "01FF0101-BA5E-F4EE-5CA1-EB1E5E4B1CE0"
+
+ val UART_SERVICE: UUID = UUID.fromString("01FF0100-BA5E-F4EE-5CA1-EB1E5E4B1CE0")
+ val UART_CHAR: UUID = UUID.fromString("01FF0101-BA5E-F4EE-5CA1-EB1E5E4B1CE0")
+
+ val service = BluetoothGattService(UART_SERVICE, BluetoothGattService.SERVICE_TYPE_PRIMARY)
+
+ val uartCharacteristic = BluetoothGattCharacteristic(UART_CHAR,
+ BluetoothGattCharacteristic.PROPERTY_WRITE,
+ BluetoothGattCharacteristic.PERMISSION_WRITE)
override fun onCreate() {
super.onCreate()
- bluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().bluetoothLeScanner
+ mBluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
+// Log.d("BMS", "writeBytes():" + cmdGeneralInfo.toHexString())
+ Log.d("BMS", "mBluetoothManager:" + mBluetoothManager)
+ if (mBluetoothManager != null) {
+ mGattServer = mBluetoothManager.openGattServer(this, mGattServerCallback);
+ }
+ val bluetoothAdapter = mBluetoothManager.adapter
+ // We can't continue without proper Bluetooth support
+ checkBluetoothSupport(bluetoothAdapter)
+
+ service.addCharacteristic(uartCharacteristic)
+ mGattServer?.addService(service) ?: Log.w(TAG, "Unable to create GATT server")
+
+ bluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().bluetoothLeScanner
startBleScanning()
}
+ /**
+ * Verify the level of Bluetooth support provided by the hardware.
+ * @param bluetoothAdapter System [BluetoothAdapter].
+ * @return true if Bluetooth is properly supported, false otherwise.
+ */
+ private fun checkBluetoothSupport(bluetoothAdapter: BluetoothAdapter?): Boolean {
+
+ if (bluetoothAdapter == null) {
+ Log.w(TAG, "Bluetooth is not supported")
+ return false
+ }
+
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
+ Log.w(TAG, "Bluetooth LE is not supported")
+ return false
+ }
+
+ return true
+ }
+
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return START_STICKY
}
@@ -49,8 +113,164 @@ class BleService : Service() {
super.onScanResult(callbackType, result)
if (result.device != null) {
+// if(
+// result.device.name != null &&
+// result.device.name.startsWith("UOOK-BMS") == true
+// ) {
+// BleManager.i.addDevice(result.device)
+// }
BleManager.i.addDevice(result.device)
}
}
}
+
+ /**
+ * Callback to handle incoming requests to the GATT server.
+ * All read/write requests for characteristics and descriptors are handled here.
+ */
+ private val mGattServerCallback = object : BluetoothGattServerCallback() {
+
+ override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
+// if (newState == BluetoothProfile.STATE_CONNECTED) {
+// Log.i(TAG, "BluetoothDevice CONNECTED: $device")
+// } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+// Log.i(TAG, "BluetoothDevice DISCONNECTED: $device")
+// //Remove device from any active subscriptions
+// registeredDevices.remove(device)
+// }
+ }
+
+ override fun onCharacteristicWriteRequest(
+ device: BluetoothDevice?,
+ requestId: Int,
+ characteristic: BluetoothGattCharacteristic?,
+ preparedWrite: Boolean,
+ responseNeeded: Boolean,
+ offset: Int,
+ value: ByteArray?
+ )
+ {
+ super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value)
+
+ var str: String = ""
+
+ if (value != null) {
+ for(vl in value) {
+ str = String.format("%02X", vl)
+ Log.d("BMS", str)
+ }
+ }
+ mGattServer?.sendResponse(
+ device,
+ requestId,
+ GATT_SUCCESS,
+ 0,
+ null
+ )
+ }
+// public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
+// throw new RuntimeException("Stub!");
+// }
+// public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
+// super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
+// String s = "";
+// for (byte vl: value) {
+// s = String.format("%02X ", vl);
+// }
+// Log.v(TAG, "Char: " + characteristic.getUuid().toString() + " offset " + offset + " Value " + s);
+//
+// if(tmp == mCurrentServiceFragment.getCharacteristicUUID().get(1))
+// {
+//
+// }
+// mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+// }
+
+ override fun onCharacteristicReadRequest(device: BluetoothDevice, requestId: Int, offset: Int,
+ characteristic: BluetoothGattCharacteristic
+ ) {
+// val now = System.currentTimeMillis()
+// when {
+// TimeProfile.CURRENT_TIME == characteristic.uuid -> {
+// Log.i(TAG, "Read CurrentTime")
+// bluetoothGattServer?.sendResponse(device,
+// requestId,
+// BluetoothGatt.GATT_SUCCESS,
+// 0,
+// TimeProfile.getExactTime(now, TimeProfile.ADJUST_NONE))
+// }
+// TimeProfile.LOCAL_TIME_INFO == characteristic.uuid -> {
+// Log.i(TAG, "Read LocalTimeInfo")
+// bluetoothGattServer?.sendResponse(device,
+// requestId,
+// BluetoothGatt.GATT_SUCCESS,
+// 0,
+// TimeProfile.getLocalTimeInfo(now))
+// }
+// else -> {
+// // Invalid characteristic
+// Log.w(TAG, "Invalid Characteristic Read: " + characteristic.uuid)
+// bluetoothGattServer?.sendResponse(device,
+// requestId,
+// BluetoothGatt.GATT_FAILURE,
+// 0,
+// null)
+// }
+// }
+ }
+
+ override fun onDescriptorReadRequest(device: BluetoothDevice, requestId: Int, offset: Int,
+ descriptor: BluetoothGattDescriptor
+ ) {
+// if (TimeProfile.CLIENT_CONFIG == descriptor.uuid) {
+// Log.d(TAG, "Config descriptor read")
+// val returnValue = if (registeredDevices.contains(device)) {
+// BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
+// } else {
+// BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
+// }
+// bluetoothGattServer?.sendResponse(device,
+// requestId,
+// BluetoothGatt.GATT_SUCCESS,
+// 0,
+// returnValue)
+// } else {
+// Log.w(TAG, "Unknown descriptor read request")
+// bluetoothGattServer?.sendResponse(device,
+// requestId,
+// BluetoothGatt.GATT_FAILURE,
+// 0, null)
+// }
+ }
+
+ override fun onDescriptorWriteRequest(device: BluetoothDevice, requestId: Int,
+ descriptor: BluetoothGattDescriptor,
+ preparedWrite: Boolean, responseNeeded: Boolean,
+ offset: Int, value: ByteArray) {
+// if (TimeProfile.CLIENT_CONFIG == descriptor.uuid) {
+// if (Arrays.equals(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE, value)) {
+// Log.d(TAG, "Subscribe device to notifications: $device")
+// registeredDevices.add(device)
+// } else if (Arrays.equals(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE, value)) {
+// Log.d(TAG, "Unsubscribe device from notifications: $device")
+// registeredDevices.remove(device)
+// }
+//
+// if (responseNeeded) {
+// bluetoothGattServer?.sendResponse(device,
+// requestId,
+// BluetoothGatt.GATT_SUCCESS,
+// 0, null)
+// }
+// } else {
+// Log.w(TAG, "Unknown descriptor write request")
+// if (responseNeeded) {
+// bluetoothGattServer?.sendResponse(device,
+// requestId,
+// BluetoothGatt.GATT_FAILURE,
+// 0, null)
+// }
+// }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BmsGattClientCallback.kt b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BmsGattClientCallback.kt
index 7cf4aed..af0bf4a 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BmsGattClientCallback.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/bluetooth/BmsGattClientCallback.kt
@@ -4,6 +4,7 @@ import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothProfile
+import android.os.Build
import android.util.Log
import de.jnns.bmsmonitor.bms.BmsCellInfoResponse
import de.jnns.bmsmonitor.bms.BmsGeneralInfoResponse
@@ -20,14 +21,18 @@ class BmsGattClientCallback(
var isConnected = false
- lateinit var readCharacteristic: BluetoothGattCharacteristic
+// lateinit var readCharacteristic: BluetoothGattCharacteristic
lateinit var writeCharacteristic: BluetoothGattCharacteristic
- private val uartUuid = UUID.fromString("0000ff00-0000-1000-8000-00805f9b34fb")
- private val rxUuid = UUID.fromString("0000ff01-0000-1000-8000-00805f9b34fb")
- private val txUuid = UUID.fromString("0000ff02-0000-1000-8000-00805f9b34fb")
+// private val uartUuid = UUID.fromString("0000A002-0000-1000-8000-00805f9b34fb")
+// private val rxUuid = UUID.fromString("0000C305-0000-1000-8000-00805f9b34fb")
+// private val txUuid = UUID.fromString("0000C302-0000-1000-8000-00805f9b34fb")
+ private val uartUuid = UUID.fromString("01FF0100-BA5E-F4EE-5CA1-EB1E5E4B1CE0")
+ private val txUuid = UUID.fromString("01FF0101-BA5E-F4EE-5CA1-EB1E5E4B1CE0")
- private val bufferSize: Int = 80
+ private var isInTrans: Boolean = false
+ private var receLen: Int = 0
+ private val bufferSize: Int = 256
private var uartBuffer = ByteArray(bufferSize)
private var uartBufferPos: Int = 0
private var uartBytesLeft: Int = 0
@@ -45,7 +50,10 @@ class BmsGattClientCallback(
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
- gatt.discoverServices()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ gatt.requestMtu(247);
+ }
+// gatt.discoverServices()
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
isConnected = false
}
@@ -55,75 +63,73 @@ class BmsGattClientCallback(
super.onServicesDiscovered(gatt, status)
if (status != BluetoothGatt.GATT_SUCCESS) {
+ Log.d("BluetoothGatt", "onServicesDiscovered failed")
return
}
val uartService = gatt.getService(uartUuid)
if (uartService != null) {
- readCharacteristic = uartService.getCharacteristic(rxUuid)
+ Log.d("BMS", "uartService:" + uartService)
+// readCharacteristic = uartService.getCharacteristic(rxUuid)
writeCharacteristic = uartService.getCharacteristic(txUuid)
-
+ Log.d("BMS", "writeCharacteristic:" + writeCharacteristic)
gatt.setCharacteristicNotification(writeCharacteristic, true)
- gatt.setCharacteristicNotification(readCharacteristic, true)
+// gatt.setCharacteristicNotification(readCharacteristic, true)
onConnectionSucceeded()
isConnected = true
}
}
+ fun setReceivingLen(receiveLen: Int) {
+ receLen = receiveLen
+ isInTrans = true
+ uartBufferPos = 0
+ }
+
+ fun isInTransaction(): Boolean {
+ return isInTrans
+ }
+
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
super.onCharacteristicChanged(gatt, characteristic)
- // Log.d("BluetoothGatt", "BLE Data (" + characteristic.value.size + "): " + characteristic.value.toHexString())
+ Log.d("BMS", "BLE Data (" + characteristic.value.size + "): " + characteristic.value.toHexString())
for (byte: Byte in characteristic.value) {
- if (uartBufferPos >= bufferSize) {
- isInFrame = false
- uartBufferPos = 0
- uartBytesLeft = 0
- }
-
uartBuffer[uartBufferPos] = byte
-
- if (isInFrame) {
- if (uartBufferPos == 3) {
- uartBytesLeft = byte.toInt()
- }
-
- if (byte.toUByte() == 0x77.toUByte() && uartBytesLeft < 1) {
- isInFrame = false
- onFrameComplete(uartBufferPos)
- uartBufferPos = 0
- uartBytesLeft = 0
- } else {
-
- uartBufferPos++
- uartBytesLeft--
- }
- } else if (byte.toUByte() == 0xDD.toUByte()) {
- isInFrame = true
- uartBufferPos++
+ uartBufferPos++
+ if (uartBufferPos >= bufferSize || uartBufferPos >= receLen) {
+ onFrameComplete(uartBufferPos)
+ Log.d("BMS", "Transaction Done.")
+ isInTrans = false
+ uartBufferPos = 0
+ break
}
}
}
+ override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
+ var mtu_size: Int = mtu
+ // Handle MTU change request from the central device
+// if (mtu_size > 247) {
+// mtu_size = 247
+// }
+// // Respond to the MTU change request
+// bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+ Log.d("BMS", "Negotiated mtu_size=" + mtu_size)
+ gatt.discoverServices()
+ }
+
private fun onFrameComplete(size: Int) {
if (size <= 0) {
return
}
- val frameBytes = uartBuffer.slice(IntRange(0, size)).toByteArray()
-
- // Log.d("BluetoothGatt", "FrameData (" + frameBytes.size + "): " + frameBytes.toHexString())
-
- if (frameBytes[1] == 0x3.toByte()) {
- val generalInfo = BmsGeneralInfoResponse(frameBytes)
- onGeneralInfoCallback(generalInfo)
- } else if (frameBytes[1] == 0x4.toByte()) {
- val cellInfo = BmsCellInfoResponse(frameBytes)
- onCellInfoCallback(cellInfo)
- }
+ val frameBytes = uartBuffer.slice(IntRange(0, size - 1)).toByteArray()
+ val generalInfo = BmsGeneralInfoResponse(frameBytes)
+ onGeneralInfoCallback(generalInfo)
}
private fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
diff --git a/app/src/main/java/de/jnns/bmsmonitor/bms/BmsGeneralInfoResponse.kt b/app/src/main/java/de/jnns/bmsmonitor/bms/BmsGeneralInfoResponse.kt
index 5cbba17..c50fc57 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/bms/BmsGeneralInfoResponse.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/bms/BmsGeneralInfoResponse.kt
@@ -5,49 +5,67 @@ import java.nio.ByteBuffer
import java.nio.ByteOrder
class BmsGeneralInfoResponse(bytes: ByteArray) {
- var command: Int = 0
- var status: Int = 0
- var dataLength: Int = 0
- var totalVoltage: Float = 0.0f
- var totalCurrent: Float = 0.0f
- var residualCapacity: Float = 0.0f
var capacity: Float = 0.0f
- var nominalCapacity: Float = 0.0f
- var temperatureProbeCount: Int = 0
- var temperatureProbeValues: RealmList
- var cycles: Short = 0
+ var sysTemperature: Float = 0.0f
+ var packCurrent: Float = 0.0f
+ var packVoltage: Float = 0.0f
+ var maxDischargeCurrent: Float = 0.0f
+ var maxChargeCurrent: Float = 0.0f
+ var bpVersion: Byte = 0
+ var bpNumber: Byte = 0
+ var packRSOC: Byte = 0
+ var packDischargCycle: Short = 0
+ var heatsinkTemperature: Float = 0.0f
+ var cellVoltage1: Float = 0.0f
+ var cellVoltage2: Float = 0.0f
+ var cellVoltage3: Float = 0.0f
+ var cellVoltage4: Float = 0.0f
+ var cellVoltage5: Float = 0.0f
+ var cellVoltage6: Float = 0.0f
+ var cellVoltage7: Float = 0.0f
+ var cellVoltage8: Float = 0.0f
+ var cellVoltage9: Float = 0.0f
+ var cellVoltage10: Float = 0.0f
+ var cellVoltage11: Float = 0.0f
+ var cellVoltage12: Float = 0.0f
+ var cellVoltage13: Float = 0.0f
+ var cellVoltage14: Float = 0.0f
+ var cellVoltage15: Float = 0.0f
+ var cellVoltage16: Float = 0.0f
- init {
- command = bytes[1].toInt()
- status = bytes[2].toInt()
- dataLength = bytes[3].toInt()
-
- totalVoltage = bytesToShort(bytes[4], bytes[5]) / 100.0f
-
- // discharging
- totalCurrent = bytesToShort(bytes[6], bytes[7]) / 100.0f
- residualCapacity = bytesToShort(bytes[8], bytes[9]) / 100.0f
- nominalCapacity = bytesToShort(bytes[10], bytes[11]) / 100.0f
- cycles = bytesToShort(bytes[12], bytes[13])
-
- // 14 & 15 = production date
- // 16 & 17 = balance low
- // 18 & 19 = balance high
- // 20 & 21 = protection status
- // 22 = version
-
- capacity = bytes[23].toInt() / 100.0f
+ init {
+ bpVersion = bytes[0]
+ bpNumber = bytes[1]
+ packRSOC = bytes[2]
+ capacity = bytesToShort(bytes[4], bytes[5]) / 10.0f
+ packVoltage = bytesToShort(bytes[8], bytes[9]) / 100.0f
+ packCurrent = bytesToShort(bytes[10], bytes[11]) / 100.0f
+ maxDischargeCurrent = bytesToShort(bytes[12], bytes[13]) / 100.0f
+ maxChargeCurrent = bytesToShort(bytes[14], bytes[15]) / 100.0f
- // 24 = MOS status
- // 25 = number of cells
+ packDischargCycle = bytesToShort(bytes[74], bytes[75])
- temperatureProbeCount = bytes[26].toInt()
- temperatureProbeValues = RealmList()
+ // System temperature
+ sysTemperature = bytesToShort(bytes[52], bytes[53]) / 100.0f
+ heatsinkTemperature = bytesToShort(bytes[54], bytes[55]) / 100.0f
- for (i in 0 until temperatureProbeCount) {
- temperatureProbeValues.add((bytesToShort(bytes[27 + (i * 2)], bytes[27 + (i * 2) + 1]) - 2731) / 10.0f)
- }
+ cellVoltage1 = bytesToShort(bytes[96], bytes[97]) / 1000.0f
+ cellVoltage2 = bytesToShort(bytes[98], bytes[99]) / 1000.0f
+ cellVoltage3 = bytesToShort(bytes[100], bytes[101]) / 1000.0f
+ cellVoltage4 = bytesToShort(bytes[102], bytes[103]) / 1000.0f
+ cellVoltage5 = bytesToShort(bytes[104], bytes[105]) / 1000.0f
+ cellVoltage6 = bytesToShort(bytes[106], bytes[107]) / 1000.0f
+ cellVoltage7 = bytesToShort(bytes[108], bytes[109]) / 1000.0f
+ cellVoltage8 = bytesToShort(bytes[110], bytes[111]) / 1000.0f
+ cellVoltage9 = bytesToShort(bytes[112], bytes[113]) / 1000.0f
+ cellVoltage10 = bytesToShort(bytes[114], bytes[115]) / 1000.0f
+ cellVoltage11 = bytesToShort(bytes[116], bytes[117]) / 1000.0f
+ cellVoltage12 = bytesToShort(bytes[118], bytes[119]) / 1000.0f
+ cellVoltage13 = bytesToShort(bytes[120], bytes[121]) / 1000.0f
+ cellVoltage14 = bytesToShort(bytes[122], bytes[123]) / 1000.0f
+ cellVoltage15 = bytesToShort(bytes[124], bytes[125]) / 1000.0f
+ cellVoltage16 = bytesToShort(bytes[126], bytes[127]) / 1000.0f
}
private fun bytesToShort(h: Byte, l: Byte, order: ByteOrder = ByteOrder.BIG_ENDIAN): Short {
diff --git a/app/src/main/java/de/jnns/bmsmonitor/data/BatteryData.kt b/app/src/main/java/de/jnns/bmsmonitor/data/BatteryData.kt
index f7f058c..1b7aaa3 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/data/BatteryData.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/data/BatteryData.kt
@@ -10,12 +10,48 @@ open class BatteryData(
var current: Float = 0.0f,
var totalCapacity: Float = 0.0f,
var currentCapacity: Float = 0.0f,
- var cycles: Int = 0,
var temperatureCount: Int = 0,
var cellCount: Int = 0,
var temperatures: RealmList = RealmList(),
- var cellVoltages: RealmList = RealmList()
+ var cellVoltages: RealmList = RealmList(),
+
+// var cycles: Short = 0,
+// var capacity: Float = 0.0f,
+// var temperature: Float = 0.0f,
+// var dischargeCurrent: Float = 0.0f,
+// var packVoltage: Float = 0.0f,
+// var chargeCurrent: Float = 0.0f,
+// var maxChargeCurrent: Float = 0.0f
+
+
) : RealmObject() {
+ var capacity: Float = 0.0f
+ var sysTemperature: Float = 0.0f
+ var packCurrent: Float = 0.0f
+ var packVoltage: Float = 0.0f
+ var maxDischargeCurrent: Float = 0.0f
+ var maxChargeCurrent: Float = 0.0f
+ var bpVersion: Byte = 0
+ var bpNumber: Byte = 0
+ var packRSOC: Byte = 0
+ var packDischargCycle: Short = 0
+ var heatsinkTemperature: Float = 0.0f
+ var cellVoltage1: Float = 0.0f
+ var cellVoltage2: Float = 0.0f
+ var cellVoltage3: Float = 0.0f
+ var cellVoltage4: Float = 0.0f
+ var cellVoltage5: Float = 0.0f
+ var cellVoltage6: Float = 0.0f
+ var cellVoltage7: Float = 0.0f
+ var cellVoltage8: Float = 0.0f
+ var cellVoltage9: Float = 0.0f
+ var cellVoltage10: Float = 0.0f
+ var cellVoltage11: Float = 0.0f
+ var cellVoltage12: Float = 0.0f
+ var cellVoltage13: Float = 0.0f
+ var cellVoltage14: Float = 0.0f
+ var cellVoltage15: Float = 0.0f
+ var cellVoltage16: Float = 0.0f
val voltage: Float
get() {
@@ -51,4 +87,5 @@ open class BatteryData(
get() {
return current * voltage
}
-}
\ No newline at end of file
+
+}
diff --git a/app/src/main/java/de/jnns/bmsmonitor/services/BmsService.kt b/app/src/main/java/de/jnns/bmsmonitor/services/BmsService.kt
index 78739b1..5a2fbf6 100644
--- a/app/src/main/java/de/jnns/bmsmonitor/services/BmsService.kt
+++ b/app/src/main/java/de/jnns/bmsmonitor/services/BmsService.kt
@@ -5,6 +5,7 @@ import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.content.Intent
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
+import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.util.Log
@@ -22,7 +23,8 @@ import io.realm.Realm
@ExperimentalUnsignedTypes
class BmsService : Service() {
// BMS commands, they won't change
- private val cmdGeneralInfo: ByteArray = ubyteArrayOf(0xDDU, 0xA5U, 0x03U, 0x00U, 0xFFU, 0xFDU, 0x77U).toByteArray()
+// private val cmdGeneralInfo: ByteArray = ubyteArrayOf(0x10U, 0x00U, 0x00U, 0x40U).toByteArray()
+ private val cmdGeneralInfo: ByteArray = ubyteArrayOf(0xA5U, 0x01U, 0x61U, 0x62U).toByteArray()
private val cmdCellInfo: ByteArray = ubyteArrayOf(0xDDU, 0xA5U, 0x04U, 0x00U, 0xFFU, 0xFCU, 0x77U).toByteArray()
private val cmdBmsVersion: ByteArray = ubyteArrayOf(0xDDU, 0xA5U, 0x05U, 0x00U, 0xFFU, 0xFBU, 0x77U).toByteArray()
@@ -35,7 +37,7 @@ class BmsService : Service() {
// it is going to toggle "dataModeSwitch" and
// request General or Cell data
private val dataHandler: Handler = Handler()
- private var dataModeSwitch = false
+// private var dataModeSwitch = false
private var dataPollDelay: Long = 0
// we need both datasets to update the view
@@ -64,7 +66,8 @@ class BmsService : Service() {
bleMac = PreferenceManager.getDefaultSharedPreferences(this).getString("macAddress", "")!!
blePin = PreferenceManager.getDefaultSharedPreferences(this).getString("blePin", "")!!
- dataPollDelay = PreferenceManager.getDefaultSharedPreferences(this).getString("refreshInterval", "1000")!!.toLong() / 2
+ dataPollDelay = PreferenceManager.getDefaultSharedPreferences(this).getString("refreshInterval", "5000")!!.toLong()
+ dataPollDelay = 5000
BleManager.i.onUpdateFunctions.add {
searchForDeviceAndConnect()
@@ -94,13 +97,38 @@ class BmsService : Service() {
return null
}
- private fun onGeneralInfoAvailable(generalInfo: BmsGeneralInfoResponse) {
- batteryData.current = generalInfo.totalCurrent
- batteryData.currentCapacity = generalInfo.residualCapacity
- batteryData.totalCapacity = generalInfo.nominalCapacity
- batteryData.temperatureCount = generalInfo.temperatureProbeCount
- batteryData.temperatures = generalInfo.temperatureProbeValues
+ override fun onDestroy() {
+ disconnectFromDevice()
+ }
+ private fun onGeneralInfoAvailable(generalInfo: BmsGeneralInfoResponse) {
+ batteryData.capacity = generalInfo.capacity
+ batteryData.sysTemperature = generalInfo.sysTemperature
+ batteryData.packCurrent = generalInfo.packCurrent
+ batteryData.packVoltage = generalInfo.packVoltage
+ batteryData.maxDischargeCurrent = generalInfo.maxDischargeCurrent
+ batteryData.maxChargeCurrent = generalInfo.maxChargeCurrent
+ batteryData.bpVersion = generalInfo.bpVersion
+ batteryData.bpNumber = generalInfo.bpNumber
+ batteryData.packRSOC = generalInfo.packRSOC
+ batteryData.packDischargCycle = generalInfo.packDischargCycle
+ batteryData.heatsinkTemperature = generalInfo.heatsinkTemperature
+ batteryData.cellVoltage1 = generalInfo.cellVoltage1
+ batteryData.cellVoltage2 = generalInfo.cellVoltage2
+ batteryData.cellVoltage3 = generalInfo.cellVoltage3
+ batteryData.cellVoltage4 = generalInfo.cellVoltage4
+ batteryData.cellVoltage5 = generalInfo.cellVoltage5
+ batteryData.cellVoltage6 = generalInfo.cellVoltage6
+ batteryData.cellVoltage7 = generalInfo.cellVoltage7
+ batteryData.cellVoltage8 = generalInfo.cellVoltage8
+ batteryData.cellVoltage9 = generalInfo.cellVoltage9
+ batteryData.cellVoltage10 = generalInfo.cellVoltage10
+ batteryData.cellVoltage11 = generalInfo.cellVoltage11
+ batteryData.cellVoltage12 = generalInfo.cellVoltage12
+ batteryData.cellVoltage13 = generalInfo.cellVoltage13
+ batteryData.cellVoltage14 = generalInfo.cellVoltage14
+ batteryData.cellVoltage15 = generalInfo.cellVoltage15
+ batteryData.cellVoltage16 = generalInfo.cellVoltage16
generalInfoReceived = true
sendData()
}
@@ -114,7 +142,7 @@ class BmsService : Service() {
}
private fun sendData() {
- if (cellInfoReceived && generalInfoReceived) {
+ if (generalInfoReceived) {
cellInfoReceived = false
generalInfoReceived = false
@@ -147,6 +175,8 @@ class BmsService : Service() {
connectToDevice()
}
+ private fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
+
private fun onConnectionSucceeded() {
isConnected = true
isConnecting = false
@@ -155,14 +185,8 @@ class BmsService : Service() {
override fun run() {
if (gattClientCallback.isConnected) {
if (isInForeground) {
- if (dataModeSwitch) {
- writeBytes(cmdGeneralInfo)
- } else {
- writeBytes(cmdCellInfo)
- }
-
- dataModeSwitch = !dataModeSwitch
-
+ Log.d("BMS", "writeBytes()1:" + cmdGeneralInfo.toHexString())
+ writeBytes(cmdGeneralInfo)
dataHandler.postDelayed(this, dataPollDelay)
}
} else {
@@ -193,8 +217,9 @@ class BmsService : Service() {
::onConnectionFailed // on connection fails
)
- currentBleDevice.setPin(blePin.toByteArray())
- currentBleDevice.createBond()
+// currentBleDevice.setPin(blePin.toByteArray())
+// currentBleDevice.createBond()
+// currentBleDevice.setPairingConfirmation(false);
bluetoothGatt = currentBleDevice.connectGatt(this, false, gattClientCallback)
}
@@ -209,6 +234,7 @@ class BmsService : Service() {
}
private fun writeBytes(bytes: ByteArray) {
+ gattClientCallback.setReceivingLen(128);
gattClientCallback.writeCharacteristic.value = bytes
bluetoothGatt.writeCharacteristic(gattClientCallback.writeCharacteristic)
}
diff --git a/app/src/main/res/drawable/selector_bottom_nav_item.xml b/app/src/main/res/drawable/selector_bottom_nav_item.xml
new file mode 100644
index 0000000..1df24fb
--- /dev/null
+++ b/app/src/main/res/drawable/selector_bottom_nav_item.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 5c26e5f..e2377d6 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -72,6 +72,8 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
+ app:itemIconTint="@drawable/selector_bottom_nav_item"
+ app:itemTextColor="@drawable/selector_bottom_nav_item"
app:menu="@menu/main_navigation_menu" />
+ app:layout_constraintEnd_toStartOf="@+id/labelPower"
+ />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -371,7 +387,7 @@
@@ -439,7 +455,7 @@
@@ -507,7 +523,7 @@
@@ -575,7 +591,7 @@
@@ -643,7 +659,7 @@
diff --git a/app/src/main/res/menu/main_navigation_menu.xml b/app/src/main/res/menu/main_navigation_menu.xml
index a79e6ff..5709988 100644
--- a/app/src/main/res/menu/main_navigation_menu.xml
+++ b/app/src/main/res/menu/main_navigation_menu.xml
@@ -7,14 +7,16 @@
android:title="@string/navBattery"/>
+ android:title="@string/navBike"
+ android:visible="false" />
+ android:title="@string/navStats"
+ android:visible="false" />
-
+ app:startDestination="@id/navigation_bms">
+
+
+
+
+
BMS Monitor
- BMS
+ UOOK BMS
Monitor
BMS Monitor - Settings
BMS Monitor - Stats
Waiting for BMS…
- BMS: %1$s
+ BMS: %2$02x%1$02x
Bike: %1$s
Power
@@ -26,7 +26,7 @@
0
0.0
- 00:00
+ Cycle:
W
V
@@ -60,4 +60,11 @@
Max Speed (Km/h)
Cell Balance
+
+ Pack Cap.:
+ Cycle:
+ Pack Vol.:
+ Disch. Curr:
+ Charge Curr:
+ Max. CC:
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index ccba39e..f0640c7 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -7,5 +7,8 @@
- @color/primary
- @color/bgBase1
- @color/bgBase
+
+ - @android:color/white
+ - @android:color/white
\ No newline at end of file
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index d683e86..a58e377 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -7,6 +7,7 @@
app:title="Bluetooth Low Energy">
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -58,66 +59,66 @@
app:title="@string/settingsRefreshInterval"
app:useSimpleSummaryProvider="true" />
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 924b026..a03ea65 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlin_version = "1.4.21"
+ ext.kotlin_version = '1.6.21'
repositories {
google()
@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.1'
+ classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.realm:realm-gradle-plugin:10.2.0"
diff --git a/gradle.properties b/gradle.properties
index 98bed16..c730713 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,7 +6,11 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+#org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+#org.gradle.jvmargs=-Xmx6g
+org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g
+
+
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
@@ -18,4 +22,5 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
-kotlin.code.style=official
\ No newline at end of file
+kotlin.code.style=official
+# android.debug.obsoleteApi=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fc56cb7..745d67d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
diff --git a/tmp.txt b/tmp.txt
new file mode 100644
index 0000000..5d89782
--- /dev/null
+++ b/tmp.txt
@@ -0,0 +1 @@
+temp 0111