Unable to read data via bluetooth successfully

2019-08-17 05:53发布

问题:

I'm trying to create an App which can receive data and send data to the microcontroller (ESP32). But for some reason, I'm unable to receive data from microcontroller successfully.

The app is written in Kotlin, and I already tried some examples mentioned on StackOverflow, but none of them actually works on my code. I can successfully send data to the microcontroller via Bluetooth, but I can't receive data from Bluetooth. (The method I used in the microcontroller is just simply "ESP_BT.println("Check");"

In the code snippet, the function relates to my receiving data is called "receiveBluetooth"

class ControlActivity: AppCompatActivity() {

    companion object {
        val myUUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
        var myBluetoothSocket: BluetoothSocket? = null
        lateinit var myProgress: ProgressDialog
        lateinit var myBluetoothAdapter: BluetoothAdapter
        var myIsConnected: Boolean = false
        lateinit var myAddress: String
        val mmInStream: InputStream? = null
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.control_layout)
        myAddress = intent.getStringExtra(SelectDeviceActivity.EXTRA_ADDRESS)

        ConnectToDevice(this).execute()
        val btnShow = findViewById<Button>(R.id.btnShow)
        var inputRPM: String
        //Read in value and store it as String
        btnShow.setOnClickListener{
            inputRPM = receiveInput()
            sendCommand(inputRPM)
        }

        //Read RPM from microcontroller (bluetooth)
        val showCountTextView = findViewById<TextView>(R.id.textView)
        btnRefresh.setOnClickListener {
            //showCountTextView.text = receiveBluetooth()
            receiveBluetooth(showCountTextView)
        }

        control_disconnect.setOnClickListener{
            disconnect()
        }
    }



    private fun receiveInput(): String {
        val input = findViewById<EditText>(R.id.editText)
        return input.text.toString()
    }

    private fun sendCommand(input: String) {
        if (myBluetoothSocket != null) {
            try{
                myBluetoothSocket!!.outputStream.write(input.toByteArray())
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    private fun receiveBluetooth(input: TextView) {
        val buffer = ByteArray(256)
        val bytes:Int
        var tmpIn: InputStream? = null
        if (myBluetoothSocket != null) {
            try {
                tmpIn = myBluetoothSocket!!.inputStream
                val mmInStream = DataInputStream(tmpIn)
                bytes = mmInStream.read(buffer)
                val readMessage = String(buffer, 0, bytes)
                input.text = readMessage
                //input.text="123"
            } catch (e:IOException) {
                e.printStackTrace()
            }
        }


    }


    private fun disconnect() {
        if (myBluetoothSocket != null) {
            try {
                myBluetoothSocket!!.close()
                myBluetoothSocket = null
                myIsConnected = false
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        finish()
    }
    private class ConnectToDevice(c: Context) : AsyncTask<Void, Void, String> () {
        private var connectSuccess: Boolean = true
        private val context: Context

        init {
            this.context = c
        }

        override fun onPreExecute() {
            super.onPreExecute()
            myProgress = ProgressDialog.show(context, "Connecting", "Please wait")
        }

        override fun doInBackground(vararg params: Void?): String? {
            try {
                if (myBluetoothSocket == null || !myIsConnected) {
                    myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
                    val device: BluetoothDevice = myBluetoothAdapter.getRemoteDevice(myAddress)
                    myBluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(myUUID)
                    BluetoothAdapter.getDefaultAdapter().cancelDiscovery()
                    myBluetoothSocket!!.connect()
                }
            } catch (e: IOException) {
                connectSuccess = false
                e.printStackTrace()
            }
            //Needs be fixed
            return null
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            if (!connectSuccess) {
                Log.i("data", "couldn't connect")
            } else {
                myIsConnected = true
            }
            myProgress.dismiss()
        }
    }
}

I expect the text will show exactly "Check", but instead, my text will only show the initial value that I assigned.

回答1:

Maybe you should use a library. For me works fine RxAndroidBle library:

Gradle:

implementation "com.polidea.rxandroidble2:rxandroidble:1.8.1"

Implementation:

In my project with Android Java and ESP32 too, I read some characteristics or values with simple implementations, for example:

public void setupNotification() {
    if (isConnected()) {
        final Disposable disposable = connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.setupNotification(charactSensorDataUuid))
                .doOnNext(notificationObservable -> { notificationHasBeenSetUp(); })
                .flatMap(notificationObservable -> notificationObservable)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::onNotificationReceived, this::onNotificationSetupFailure);
        compositeDisposable.add(disposable);
    }
}

public void readSensorConfig(){
    if (isConnected()) {
        final Disposable disposable = connectionObservable
                .firstOrError()
                .flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(charactConfigUuid))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::onSensorConfigRead, this::onReadFailure);
        compositeDisposable.add(disposable);
    }
}

public void readSensorData(){
    if (isConnected()) {
        final Disposable disposable = connectionObservable
                .firstOrError()
                .flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(charactSensorDataUuid))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::onSensorDataRead, this::onReadFailure);
        compositeDisposable.add(disposable);
    }
}

The complete Java implementation is here:

https://github.com/kike-canaries/android-hpma115s0/blob/master/app/src/main/java/hpsaturn/pollutionreporter/common/BLEHandler.java

The migration to Kotlin should be simple, also on this library the main target is Bluetooth BLE, and they have many samples on Kotlin