Im having some issues with retrieving data from my OBDII Adapter. The issue is divided into 2 parts, which maybe are related to each other. I want to mention at the beginning that the issue should not be related to the Adapter since it worked a few weeks ago. It gave me correct values and did only crash a few times at the beginning. Since i did some changes it started to not work at all.
Issue 1 The first issue is that i get weird data from my Adapter. Im retrieving Vehicle Speed and Engine RPM with the Kotlin OBD API from Elton Viana.
Issue 2 The second issue is that after starting to retrieve data my app crashes after a few seconds with the error message: channel 'a7785b2 com.anonymous.ecodrive/com.anonymous.ecodrive.EcoLiveActivity (server)' ~ Channel is unrecoverably broken and will be disposed! I cant find much information about this issue. Some mention it could be memory leaks, but i can't find the issue after many days of analysis and testing.
UPDATE I solved the first issue. I learned that the Adapter is always resetting itself after taking it off the car. I made the initialization part of the connecting process, so it always has the correct settings. The second issue is partially still there. I found out that the reason for the first app crash is, that the first respond of my Adapter always includes something like "BUS INIT:". This message cant be handled by the OBD API so the App crashes. So after putting the Adapter in the first crash is expected. Generally the second time connecting everything works, but sometimes i need a few more tries, which i cant understand. Also rarely the app crashes during driving, so after im getting correct data for a while. I guess its somehow related to memory leaks again, but im not sure. Still the app is now working much better and quite usable as a prototype. I hope this information will help others in their work.
This is the way im connecting to my Adapter in MainActivity through the method ConnectToDevice():
private fun pairedDeviceList(){
m_pairedDevices = m_bluetoothAdapter.bondedDevices
val list: ArrayList<BluetoothDevice> = ArrayList()
if(m_pairedDevices.isNotEmpty()){
for (device: BluetoothDevice in m_pairedDevices){
list.add(device)
Log.i("device", "" + device)
}
}
else {
Toast.makeText(activity, "keine gekoppelten Geräte gefunden", Toast.LENGTH_SHORT).show()
return
}
val deviceNames = list.map { it.name }.toTypedArray()
activity?.let {
AlertDialog.Builder(it)
.setTitle("Gekoppelte Geräte")
.setItems(deviceNames) { dialog, which ->
val selectedDevice: BluetoothDevice = list[which]
m_address = selectedDevice.address
val name: String = selectedDevice.name
BluetoothHandling.ConnectToDevice(requireActivity(),requireActivity(), selectedDevice).execute()
dialog.dismiss()
}
.show()
}
}
The ConnectToDevice class in BluetoothHandling.kt looks like the following:
class ConnectToDevice(private val activity: Activity, c: Context, device: BluetoothDevice) : AsyncTask<Void, Void, String>(){
private var connectSuccess: Boolean = true
private val context: Context
private val dev = device
private lateinit var m_progress: ProgressDialog
init {
this.context = c
}
override fun onPreExecute() {
super.onPreExecute()
m_progress = ProgressDialog.show(context, "", "Connection will be established...")
}
@SuppressLint("MissingPermission")
override fun doInBackground(vararg p0: Void?): String? {
try {
if (m_bluetoothSocket == null || !m_isConnected){
m_bluetoothSocket = dev.createRfcommSocketToServiceRecord(randomUUID)
m_bluetoothSocket!!.connect()
inputStream = m_bluetoothSocket!!.inputStream
outputStream = m_bluetoothSocket!!.outputStream
obdConnection = ObdDeviceConnection(inputStream, outputStream)
}
}
catch (e: IOException){
Log.w("data","Did not work!")
connectSuccess = false
e.printStackTrace()
}
return null
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
m_progress.dismiss()
if(!connectSuccess){
Log.i("data", "CONNECTION FAILED")
Toast.makeText(context,"Connection Failed", Toast.LENGTH_SHORT).show()
}
else {
m_isConnected = true
Log.i("data", "CONNECTION SUCCESS")
val intent = Intent(context, EcoLiveActivity::class.java)
context.startActivity(intent)
activity.finish()
}
}
}
After that the EcoLiveActivity starts, where the User should starts the repeatRequests() Function by pressing the startStopBtn. The relevant Code looks like this:
private fun repeatRequests() {
if (ecoLiveActive.value == true && m_isConnected) {
CoroutineScope(Dispatchers.IO).launch {
if (m_bluetoothSocket != null) {
requestVehicleSpeed()
requestEngineRPM()
}
}
handler.postDelayed({ repeatRequests() }, 500L)
}
}
private suspend fun requestVehicleSpeed() {
try {
val response = obdConnection.run(SpeedCommand())
val output = response.value
Log.i("data", "Speed: $output")
currentSpeed = output.toInt()
viewModel.updateCurrentSpeed(currentSpeed)
} catch (e: IOException) {
Log.w("data", "Requesting vehicle speed didn't work!")
e.printStackTrace()
}
}
private suspend fun requestEngineRPM() {
try {
val response = obdConnection.run(RPMCommand())
val output = response.value
currentRPM = output.toInt()
viewModel.updateCurrentRPM(currentRPM)
Log.i("data", "RPM: $output")
withContext(Dispatchers.Main) {
rpmBar.speedTo(currentRPM.toFloat())
}
} catch (e: IOException) {
Log.w("data", "Requesting engine speed didn't work!")
e.printStackTrace()
}
}
The Logging output has some weird values for RPM and Vehicle Speed as shown following: Error Log