android Kotlin socket scanner.hasNext() has No response - android

Server-side language: Python
Client-side language: Kotlin, Android
It receives data from different lines at one line.
class SampleActivity : AppCompatActivity() {
private val TAG = "SAMPLE_ACTIVITY_TAG"
private lateinit var editTextMessage: EditText
private val IPs = listOf("192.168.100.30")
private val PORTs = listOf(5050)
private val INDEX_SERVER = 0
private var socket: Socket? = null
private val IP = IPs[INDEX_SERVER]
private val PORT = PORTs[INDEX_SERVER]
private lateinit var outPrintWriter: PrintWriter
private val CONNECTION_TOKEN = "fab2bd65f67193d761c06b07a708d3232f0d8569"
private val TAG_CONNECT_START = "[CONNECT]"
private val TAG_CONNECT_END = "[/CONNECT]"
private val TAG_TRANSFER_START = "[TRANSFER]"
private val TAG_TRANSFER_END = "[/TRANSFER]"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
editTextMessage = findViewById(R.id.editTextMessage)
CoroutineScope(Dispatchers.IO).launch {
connect()
}
buttonSubmit.setOnClickListener {
if(editTextMessage.text.toString().trim().isEmpty()){
return#setOnClickListener
}
CoroutineScope(Dispatchers.IO).launch {
send(messageConverter(TAG_TRANSFER_START + editTextMessage.text.toString().trim() + TAG_TRANSFER_END))
}
}
}
override fun onDestroy() {
outPrintWriter.close()
super.onDestroy()
}
private fun messageConverter(text: String): String {
Log.w(TAG, "[CONVERTING] \nMessage: $text\nAscii: ${text.toASCII()}")
return text.toASCII() // Defined in extention.kt
}
private suspend fun connect() {
try {
Log.w(TAG, "[CONNECTING] Connecting to: $IP:$PORT")
socket = Socket(IP, PORT)
socket?.receiveBufferSize = 1024
socket?.soTimeout = 1 * 60 * 60
outPrintWriter = PrintWriter(socket!!.getOutputStream())
send(messageConverter(TAG_CONNECT_START + CONNECTION_TOKEN + TAG_CONNECT_END))
receive()
} catch (uHE: UnknownHostException) {
Log.e(TAG, "[ERROR] UnknownHostException, ${uHE.message}", uHE)
} catch (eIO: IOException) {
Log.e(TAG, "[ERROR] IOException, ${eIO.message}", eIO)
} catch (e: Exception) {
Log.e(TAG, "[ERROR] Exception, ${e.message}", e)
}
}
private suspend fun send(text: String) {
try {
Log.w(TAG, "[SENDING] Message: $text")
outPrintWriter.print(text)
outPrintWriter.flush()
Log.w(TAG, "[SENDING] finished .")
clearMessageBox()
} catch (eIO: IOException) {
Log.e(TAG, "[ERROR] IOException, ${eIO.message}", eIO)
} catch (e: Exception) {
Log.e(TAG, "[ERROR] IOException, ${e.message}", e)
}
}
private suspend fun receive() {
try {
val scanner = Scanner(
socket?.getInputStream()
)
val lines = ArrayList<String>()
var line: String?
while (scanner.hasNextLine()) {
Logger.w(TAG, "[RECEIVING] Scanner hasNext")
line = scanner.nextLine()
if (!line.isNullOrEmpty()) {
lines.add(line)
}
}
Logger.w(TAG, "[RECEIVING] Exit While loop : ${lines}")
} catch (eIO: IOException) {
Log.e(TAG, "[ERROR] Receive IOException error: ${eIO.message}", eIO)
} catch (e: Exception) {
Log.e(TAG, "[ERROR] Receive Exception error: ${e.message}", e)
}
}
private suspend fun clearMessageBox() {
withContext(Main) {
editTextMessage.text.clear()
}
}
}
Logs:
[CONNECTING] Connecting to: 192.168.100.30:5050
[CONVERTING]
Message: [CONNECT]fab2bd65f67193d761c06b07a708d3232f0d8569[/CONNECT]
Ascii: 91,67,79,78,78,69,67,84,93,102,97,98,50,98,51,50,102,48,100,49,55,56,99,48,54,55,48,56,53,55,97,100,54,53,102,54,54,98,48,100,51,50,57,49,57,51,100,55,54,91,47,67,79,78,78,69,67,84,93
[SENDING] Message: 91,67,79,78,78,69,67,84,93,102,97,98,50,98,51,50,102,48,100,49,55,56,99,48,54,55,48,56,53,55,97,100,54,53,102,54,54,98,48,100,51,50,57,49,57,51,100,55,54,91,47,67,79,78,78,69,67,84,93
[SENDING] finished.
[RECEIVING] Scanner hasNext
[RECEIVING] Exit While loop : [OK1OK2]
Log: **[RECEIVING] Exit While loop :** shall be `[OK1, OK2]`
Server send messagesin every second twice
I just checked some questions and samples b, unfortunately in my case, no one solved the above issue

Related

How to get variables out from a asynctask + try & catch block in kotlin (android studio)?

In these below two functions I am getting referrerUrl and addId. I want both of them to be fetched in onCreate but don't know how because it is in try & catch block also the getGaid() function is not running without AsyncTask.
fun getreferrUrl() {
//to install referrer client
val referrerClient = InstallReferrerClient.newBuilder(this).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerResponse.OK -> {
// Connection established.
try {
val response: ReferrerDetails = referrerClient.installReferrer
val referrerUrl = response.installReferrer
// here we need referrerUrl out from this fuction
} catch (e: RemoteException) {
e.printStackTrace()
}
}
//
fun getGaid() {
AsyncTask.execute {
try {
val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(this)
val myId: String = if (adInfo != null) adInfo.id else null.toString()
//here we need myId out from this fuction
} catch (e: java.lang.Exception) {...}
}
}
In onCreate we need both of those strings.
// In onCreate
val url = "http://instbng.com?device_id=$device_id&
&kd_id=$kd_id&ref=$referrerUrl&gaid=$myId"
loadUrl(url)
Without coroutines, you can put the results in properties, and create a function that uses both properties and call it from both callbacks. I renamed your get... functions to fetch... since they are asynchronous. The word get in a function name implies they are synchronous.
private var referrerUrl: String? = null
private var myId: String? = null
override fun onCreate(bundle: SavedInstanceState?) {
super.onCreate(bundle)
//...
fetchReferrerUrl()
fetchGaId()
}
// proceeds with workflow if referrerUrl and myId are both available
private fun proceedIfReady() {
val referrer = referrerUrl ?: return
val id = myId ?: return
val url = "http://instbng.com?device_id=$device_id&kd_id=$kd_id&ref=$referrer&gaid=$idd"
loadUrl(url)
}
fun fetchReferrerUrl() {
val referrerClient = InstallReferrerClient.newBuilder(this).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerResponse.OK -> {
// Connection established.
try {
val response: ReferrerDetails = referrerClient.installReferrer
referrerUrl = response.installReferrer
proceedIfReady()
} catch (e: RemoteException) {
e.printStackTrace()
}
}
}
}
//... handle closed connection callback
}
}
private fun fetchGaId() {
AsyncTask.execute {
try {
val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(this)
runOnUiThread { // in a Fragment use view?.post
myId = if (adInfo != null) adInfo.id else null.toString()
proceedIfReady()
}
} catch (e: java.lang.Exception) {...}
}
}

How to connect BT barcode reader correctly?

I have two type of BT reader on of them is a Symbol CS3070 and the other one is a Datalogic DBT6400.
For the DBT6400 device I found an Android SDK with which the connection is very simple. But for the first one there is no supported SDK.
So I decided to connect to these device directly without SDK. Everything works fine,until the device disconnected because of sleep mode or because of I switch from one to another device.
In this case I get a lot of exception inside the while loop, because of the socket is closed. I have a tip for this why it's happen, maybe because of the coroutine, if it is possible.
UPDATE: So I found the problem, a put the catch block this line of code: reader=0, and there is only 1 error, so it's seems good. But I still don't know, is it a good solution?
My CustomReader class
class CustomReader(
private val deviceName: String,
onBarcodeRead: (barcode: String?) -> Unit
) : BarcodeReader(onBarcodeRead), CoroutineScope {
private val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
private var pairedDevices: Set<BluetoothDevice>? = null
private var device: BluetoothDevice? = null
private lateinit var uuid: UUID
private var socket: BluetoothSocket? = null
private var connected: Boolean = false
private val localJob: Job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + localJob
override fun init(context: Context) {
pairedDevices = bluetoothAdapter.bondedDevices
}
override fun connect(address: String) {
try {
bluetoothAdapter.startDiscovery()
uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
device = pairedDevices?.firstOrNull { x -> x.name.startsWith(deviceName) }
if(device == null){
Timber.d("CustomReader: $deviceName: Device not found")
return
}
initSocket()
launch {
run()
}
} catch (e: Exception) {
Timber.e(e)
}
}
override fun disconnect() {
try {
socket?.close()
socket = null
} catch (e: IOException) {
Timber.d("CustomReader: $deviceName: Socket closed")
}
localJob.cancel()
}
override fun destroy() {
try {
socket?.close()
socket = null
} catch (e: IOException) {
Timber.d("CustomReader: $deviceName: Socket closed")
}
localJob.cancel()
}
override fun getAddress(): String? {
return device?.address
}
override fun isConnected(): Boolean {
return connected
}
private suspend fun run() {
try {
socket?.let { socket ->
socket.connect()
connected = true
val buffer = ByteArray(1024)
var read = 0
do {
try {
read = socket.inputStream.read(buffer)
val data = String(buffer, 0, read)
onBarcodeRead.invoke(data)
} catch (e: Exception) {
Timber.e(e)
}
} while (read > 0)
CoroutineScope()
}
}catch (e: Exception){
Timber.d("CustomReader: $deviceName Disconnected")
connected = false
}
}
fun initSocket(){
if(socket != null)
return
socket = device?.createRfcommSocketToServiceRecord(uuid)
bluetoothAdapter.cancelDiscovery()
}
fun closeSocket(){
try {
socket?.close()
}catch (e: Exception){
Timber.d("CustomReader: $deviceName: Socket closed")
}
}
}
**BletoothHandlar class:**
object BluetoothHandler {
#JvmStatic
private var currentReader: BarcodeReader? = null
#JvmStatic
private val barcodeLiveData = MutableLiveData<EventWrapper<String?>>()
#JvmStatic
fun getData(): LiveData<EventWrapper<String?>> = barcodeLiveData
init {
fixedRateTimer(
name = "blueooth-reconnect",
daemon = true,
initialDelay = 0L,
period = 5000
) {
if (currentReader == null) {
Timber.d("No reader device connected")
return#fixedRateTimer
}
if (currentReader?.isConnected() == true) {
Timber.d("reader connected, doing nothing")
} else if (currentReader?.isConnected() == false) {
Timber.d("reader not connected, reconnecting")
currentReader?.connect(currentReader!!.getAddress()!!)
}
}
}
#JvmStatic
fun connectToDevice(device: BluetoothDeviceCustom, context: Context): BarcodeReader? {
if (device.address == currentReader?.getAddress() && currentReader?.isConnected() == true) {
Timber.d("device already connected")
return currentReader
}
//ha változott a kiválasztott olvasó
if (device.address != currentReader?.getAddress()) {
currentReader?.disconnect()
}
val reader = createReader(device)
if (reader == null) {
currentReader?.disconnect()
} else {
reader.init(context)
reader.connect(device.address)
}
currentReader = reader
return reader
}
#JvmStatic
fun disconnect() {
currentReader?.disconnect()
currentReader?.destroy()
currentReader = null
}
#JvmStatic
fun getConnectedDevice(): BarcodeReader? {
return currentReader
}
#JvmStatic
private fun createReader(bluetoothDeviceCustom: BluetoothDeviceCustom): BarcodeReader? {
return CustomReader(bluetoothDeviceCustom.name) {
barcodeLiveData.postValue(EventWrapper(it))
}
/*return if (bluetoothDeviceCustom.name.startsWith("DBT6400")) {
DatalogicDBT6400 {
barcodeLiveData.postValue(EventWrapper(it))
}
} else if (bluetoothDeviceCustom.name.startsWith("CS3070")) {
CustomReader(bluetoothDeviceCustom.name) {
barcodeLiveData.postValue(EventWrapper(it))
}
} else {
null
}*/
}
}
So, here it is my solution, I don't think it is the best, but it works.
const val UUID_STRING = "00001101-0000-1000-8000-00805F9B34FB"
class CustomReader(
onBarcodeRead: (barcode: String?) -> Unit
) : BarcodeReader(onBarcodeRead), CoroutineScope {
private val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
private var pairedDevices: Set<BluetoothDevice>? = null
private var device: BluetoothDevice? = null
private var socket: BluetoothSocket? = null
private val localJob: Job = Job()
private var deviceName = ""
private val uuid = UUID.fromString(UUID_STRING)
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + localJob
override fun init(context: Context) {
pairedDevices = bluetoothAdapter.bondedDevices
}
private val singleExecutor: ExecutorCoroutineDispatcher =
Executors.newFixedThreadPool(1).asCoroutineDispatcher()
override fun connect(address: String) {
try {
device = pairedDevices?.firstOrNull { x -> x.address == address }
if(device == null){
Timber.d("CustomReader: $deviceName: Device not found")
return
}
deviceName = device?.name ?: "N/A"
initSocket()
launch {
withContext(singleExecutor){
run()
}
}
} catch (e: Exception) {
Timber.e(e)
}
}
override fun disconnect() {
closeSocket()
localJob.cancel()
}
override fun getAddress(): String? {
return device?.address
}
override fun isConnected(): Boolean {
return socket?.isConnected ?: false
}
private suspend fun run() {
try {
socket?.let { socket ->
socket.connect()
val buffer = ByteArray(1024)
var read = 0
do {
try {
read = socket.inputStream.read(buffer)
val data = String(buffer, 0, read)
onBarcodeRead.invoke(data)
} catch (e: Exception) {
Timber.d("CustomReader: $deviceName Socket disconnected")
read = -1
closeSocket()
}
} while (read > 0)
}
}catch (e: Exception){
Timber.d("CustomReader : $deviceName Disconnected")
}
}
private fun closeSocket(){
try {
socket?.close()
}catch (e: IOException){
Timber.d("CustomReader: $deviceName Socket closed")
}
socket = null
}
private fun initSocket(){
if(socket != null)
return
socket = device?.createRfcommSocketToServiceRecord(uuid)
}
}

Message not received from Android MQTT publish to RabbitMQ

I have set up RabbitMQ, enabled web UI for management, enabled mqtt_plugin and the ports 1883, 8883, 5672, 15672 (Docker). I used Paho MqttClient for Android app I am developing to publish a message to the MQ broker. The connection is fine however, there is no message received as a check on the web UI and CLI.
Connection Page:
Channel Page:
Exchange Page:
Queues Page:
Below is the code I'm working on.
private static final String CONNECTION_URL = "tcp://my-app.com:1883";
private static final String USERNAME = "test_user";
private static final String PASSWORD = "test_pass";
private static final String EXCHANGE = "TestExchange";
private static final String QUEUE = "TestQueue";
private static final String TOPIC = "TestTopic";
// executed onCreate
private void initializeMQ() {
Log.d(TAG, "==== STARTING MQTT CONNECTION ====");
String clientId = "Skwamiyou";
client = new MqttAndroidClient(this, CONNECTION_URL, clientId);
MqttConnectOptions options = setConnectionOptions(USERNAME, PASSWORD);
try {
IMqttToken token = client.connect(options);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "Connected");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.d(TAG, "Failed connection");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
private static MqttConnectOptions setConnectionOptions(String username, String password) {
MqttConnectOptions options = new MqttConnectOptions();
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
options.setCleanSession(false);
options.setAutomaticReconnect(true);
options.setUserName(username);
options.setPassword(password.toCharArray());
return options;
}
// this is called on button click publish
public void publishLog() {
Log.d(TAG, "Publishing....");
counter++;
String payload = "Send to My MQ! - " + counter;
try {
MqttMessage message = new MqttMessage(payload.getBytes());
message.setQos(1);
message.setRetained(true);
client.publish(TOPIC, message);
Toast.makeText(this, "MESSAGE SENT! - " + counter, Toast.LENGTH_SHORT).show();
} catch (MqttException e) {
e.printStackTrace();
}
}
I've been looking around for answers and tried reinstalling MQ but still got the same.
Here, is common extention for coonectMq and getting message from it. (MqConnectionExtention.kt)
fun Context.connectMq(publishTopicChannelName: String, onConnectionSuccess: (topic: String?, message: MqttMessage?) -> Unit) {
val mClientId = BuildConfig.CLIENT_ID + System.currentTimeMillis()
val mqttAndroidClient = MqttAndroidClient(this, "tcp://34.212.00.188:1883", mClientId)
Timber.e("ChannelName:$publishTopicChannelName")
mqttAndroidClient.setCallback(object : MqttCallbackExtended {
override fun connectComplete(reconnect: Boolean, serverURI: String) {
if (reconnect) { //addToHistory("Reconnected to : " + serverURI)
Log.e("TAG", "Reconnected to : $serverURI")
// Because Clean Session is true, we need to re-subscribe
try {
mqttAndroidClient.subscribe(publishTopicChannelName, 0, object : IMqttMessageListener {
override fun messageArrived(topic: String?, message: MqttMessage?) {
onConnectionSuccess(topic, message)
}
})
} catch (ex: MqttException) {
System.err.println("Exception whilst subscribing")
ex.printStackTrace()
}
} else { //addToHistory("Connected to: " + serverURI);
Log.e("TAG", "Connected to: $serverURI")
}
}
override fun connectionLost(cause: Throwable) {
Log.e("TAG", "The Connection was lost.")
}
override fun messageArrived(topic: String, message: MqttMessage) {
Log.e("TAG", "Incoming message: " + message.payload.toString())
}
override fun deliveryComplete(token: IMqttDeliveryToken) {}
})
val mqttConnectOptions = setUpConnectionOptions("MQ_CONNECTION_USERNAME", "MQ_CONNECTION_PASSWORD")
mqttConnectOptions.isAutomaticReconnect = true
mqttConnectOptions.isCleanSession = false
try {
mqttAndroidClient.connect(mqttConnectOptions, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken) {
val disconnectedBufferOptions = DisconnectedBufferOptions()
disconnectedBufferOptions.isBufferEnabled = true
disconnectedBufferOptions.bufferSize = 100
disconnectedBufferOptions.isPersistBuffer = false
disconnectedBufferOptions.isDeleteOldestMessages = false
mqttAndroidClient.setBufferOpts(disconnectedBufferOptions)
try {
mqttAndroidClient.subscribe(publishTopicChannelName, 0, object : IMqttMessageListener {
override fun messageArrived(topic: String?, message: MqttMessage?) {
onConnectionSuccess(topic, message)
}
})
} catch (ex: MqttException) {
System.err.println("Exception whilst subscribing")
ex.printStackTrace()
}
}
override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) { //addToHistory("Failed to connect to: " + serverUri);
}
})
} catch (ex: MqttException) {
ex.printStackTrace()
}
}
private fun setUpConnectionOptions(username: String, password: String): MqttConnectOptions {
val connOpts = MqttConnectOptions()
connOpts.isCleanSession = true
connOpts.userName = username
connOpts.password = password.toCharArray()
return connOpts
}
From Java class I am calling it like below and getting message successfully:
private void subscribeMQForVideo() {
MqConnectionExtentionKt.connectMq(mContext, "mq_video_channel_name", (topic, mqttMessage) -> {
// message Arrived!
Log.e("TAG", "Message Video: " + topic + " : " + new String(mqttMessage.getPayload()));
return null;
});
}
To publish message similar extention I have created with little difference. (MqConnectionPublishExtention.kt)
fun Context.connectMq(onConnectionSuccess: (mqttAndroidClient: MqttAndroidClient?) -> Unit) {
val mClientId = BuildConfig.CLIENT_ID + System.currentTimeMillis()
val mqttAndroidClient = MqttAndroidClient(this, BuildConfig.MQ_SERVER_URI, mClientId)
mqttAndroidClient.setCallback(object : MqttCallbackExtended {
override fun connectComplete(reconnect: Boolean, serverURI: String) {
if (reconnect) { //addToHistory("Reconnected to : " + serverURI)
Log.e("TAG", "Reconnected to : $serverURI")
// Because Clean Session is true, we need to re-subscribe
onConnectionSuccess(mqttAndroidClient)
} else { //addToHistory("Connected to: " + serverURI);
Log.e("TAG", "Connected to: $serverURI")
}
}
override fun connectionLost(cause: Throwable) {
Log.e("TAG", "The Connection was lost.")
}
override fun messageArrived(topic: String, message: MqttMessage) {
Log.e("TAG", "Incoming message: " + message.payload.toString())
}
override fun deliveryComplete(token: IMqttDeliveryToken) {}
})
val mqttConnectOptions = setUpConnectionOptions(BuildConfig.MQ_CONNECTION_USERNAME, BuildConfig.MQ_CONNECTION_PASSWORD)
mqttConnectOptions.isAutomaticReconnect = true
mqttConnectOptions.isCleanSession = false
try {
mqttAndroidClient.connect(mqttConnectOptions, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken) {
val disconnectedBufferOptions = DisconnectedBufferOptions()
disconnectedBufferOptions.isBufferEnabled = true
disconnectedBufferOptions.bufferSize = 100
disconnectedBufferOptions.isPersistBuffer = false
disconnectedBufferOptions.isDeleteOldestMessages = false
mqttAndroidClient.setBufferOpts(disconnectedBufferOptions)
onConnectionSuccess(mqttAndroidClient)
}
override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) { //addToHistory("Failed to connect to: " + serverUri);
}
})
} catch (ex: MqttException) {
ex.printStackTrace()
}
}
private fun setUpConnectionOptions(username: String, password: String): MqttConnectOptions {
val connOpts = MqttConnectOptions()
connOpts.isCleanSession = true
connOpts.userName = username
connOpts.password = password.toCharArray()
return connOpts
}
Publish message from java class
private void publishExerciseDataToMQChannel() {
MqConnectionPublishExtentionKt.connectMq(mContext, (mqttAndroidClient) -> {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("params", mlParams);
jsonObject.put("workoutid", workoutId);
jsonObject.put("userid", model.getUserIdFromPrefs());
jsonObject.put("stream_id", streamDataModel.getStreamId());
MqttMessage message = new MqttMessage();
message.setPayload(jsonObject.toString().getBytes());
mqttAndroidClient.publish("Channel_name", message);
Log.e("TAG", message.getQos() + "");
if (!mqttAndroidClient.isConnected()) {
Log.e("TAG", mqttAndroidClient.getBufferedMessageCount() + " messages in buffer.");
}
} catch (MqttException e) {
System.err.println("Error Publishing: " + e.getMessage());
e.printStackTrace();
} catch (JSONException e) {
System.err.println("Error Publishing: " + e.getMessage());
e.printStackTrace();
}
return null;
});
}

Unable to read data via bluetooth successfully

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.
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

Bt Socket closed exception

I am building an app that is supposed to send a file over a Bluetooth socket but for some reason i keep getting the same Exception. The error message says that the socket is already closed but i don't understand how or why it is getting closed before i attempt to read from it. The user is presented with an AlertDialog with options to choose from. they are supposed to: 1. Pair to a device. 2. send file to device (currently labeled 'connect' in dialog). The exception occurs after the devices are paired, when the connect option is selected. when the receiving device attempts to read from socket i get this exception:
Process: com.example.zemcd.toofxchange, PID: 1074
java.io.IOException: bt socket closed, read return: -1
at android.bluetooth.BluetoothSocket.read(BluetoothSocket.java:588)
at android.bluetooth.BluetoothInputStream.read(BluetoothInputStream.java:96)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:273)
at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at kotlin.io.ByteStreamsKt.copyTo(IOStreams.kt:101)
at kotlin.io.ByteStreamsKt.copyTo$default(IOStreams.kt:98)
at kotlin.io.ByteStreamsKt.readBytes(IOStreams.kt:117)
at com.example.zemcd.toofxchange.BluetoothUtils$Companion.receiveFile(BluetoothUtils.kt:82)
at com.example.zemcd.toofxchange.ListenThread$run$acceptThread$1.run(BluetoothUtils.kt:104)
at java.lang.Thread.run(Thread.java:761)
below are the functions used for pair, unpair, and connect (to send data) along with the threads subclasses that used:
class BluetoothUtils {
companion object {
var listener: ListenThread? = null
val _UUID = UUID.fromString("a0e7e4c7-0e4e-43b7-9d18-659192512164")
val TAG = "BluetoothUtils"
val receiver = MainBTStatusReceiver()
fun initPairingServer(adapter: BluetoothAdapter){
var mmServerSocket: BluetoothServerSocket?
try {
var tmp = adapter.listenUsingRfcommWithServiceRecord(TAG, _UUID)
mmServerSocket = tmp
listener = ListenThread(mmServerSocket)
listener!!.start()
}catch (ioe: IOException){
Log.e(TAG, "Error initializing Bluetooth", ioe)
}
}
fun cancelListener() = listener!!.cancel()
fun connect(adapter: BluetoothAdapter, device: BluetoothDevice):Unit{
var btSocket: BluetoothSocket?
Log.d(TAG, "connect function called")
if (device.bondState==BluetoothDevice.BOND_NONE)return //to prompt user to pair
try {
adapter.cancelDiscovery()
btSocket = device.createRfcommSocketToServiceRecord(_UUID)
ConnectThread(btSocket).start()
}catch (ioe: IOException){
Log.e(TAG, "error connecting", ioe)
}
}
fun startPair(adapter: BluetoothAdapter, device: BluetoothDevice): Unit{
adapter.cancelDiscovery()
Log.d(TAG, device.bondState.toString())
device.createBond()
}
fun unPair(device: BluetoothDevice): Any = device::class.java.getMethod("removeBond").invoke(device)
fun sendFile(btSocket: BluetoothSocket){
val out = btSocket.outputStream.buffered()
out.use {
val msg = "hello".toByteArray()
Log.d(TAG, "sending data")
it.write(msg, 0, msg.size)
it.flush()
}
btSocket.close()
}
fun receiveFile(btSocket: BluetoothSocket){
Log.d(TAG, "receiveFile called")
val inStream = btSocket.inputStream.buffered()
//val bytes: ByteArray = ByteArray(1024)
val bytes: ByteArray = inStream.use { it.readBytes(1024)}
Log.d(TAG, bytes.toString())
btSocket.close()
}
}
}
class ListenThread(val btServSock: BluetoothServerSocket) : Thread(){
companion object {
val TAG = "ListenThread"
}
var btSocket: BluetoothSocket? = null
override fun run() {
super.run()
while (true){
try {
Log.d(TAG, "listening . . . ")
btSocket = btServSock.accept()
Log.d(TAG, btSocket.toString() + " was accepted")
val acceptThread = Thread(Runnable { BluetoothUtils.receiveFile(btSocket!!) })
acceptThread.start()
}catch (ioe: IOException){
Log.e(TAG, "Error", ioe)
break
}
}
}
fun cancel() = btServSock.close()
}
class ConnectThread(val btSocket: BluetoothSocket) : Thread(){
companion object {
val TAG = "Pairing Thread"
}
override fun run() {
super.run()
try {
Log.d(TAG, "attempting to connect")
btSocket.connect()
BluetoothUtils.sendFile(btSocket)
}catch (ioe: IOException){
Log.e(TAG, "error connecting", ioe)
btSocket.close()
}
}
}
and they are called like this inside of OnClickListener:
ops.forEach { it.setOnClickListener {
Toast.makeText(it.context, it.id.toString(), Toast.LENGTH_SHORT).show()
when(it.id){
R.id.statOp -> {}
R.id.connectOp -> {
Log.d(TAG, "connectOp reached")
BluetoothUtils.connect(BluetoothAdapter.getDefaultAdapter(), btDevice)
dialog!!.dismiss()
}
R.id.pairOp -> {
Log.d(TAG, "pairOp reached")
mReceiver.setFocus(this#DeviceHolder)
BluetoothUtils.startPair(BluetoothAdapter.getDefaultAdapter(), btDevice)
Log.d(TAG, "start pair complete")
dialog!!.dismiss()
}
R.id.unPairOp -> {
Log.d(TAG, "unPairOp reached")
mReceiver.setFocus(this#DeviceHolder)
BluetoothUtils.unPair(btDevice)
Log.d(TAG, "unpair complete")
dialog!!.dismiss()
}
R.id.sendOp -> {}
}
} }
and here is my with resources function:
inline fun <T: AutoCloseable, U> withResources(resource: T, fn: (T) -> U) : U{
try {
return fn(resource)
}finally {
resource.close()
}
}
please help me find my mistake. if other pieces of my code are needed let me know and i will post them. thank you for your help.

Categories

Resources