I'm new to both java and android and I am currently working on a simple data logging app for information sent via bluetooth. I have recently switched to using an HM-10 (CC41) BLE module from classic bluetooth. Since I don't know anything about using Gatt characteristics to create a connection and receive data, I would like to continue using socket communication. My phone S7 edge is not able to pair to the BLE device though so it's not an option for me to create a bond programatically before starting the RfcommSocket. Is there any way to continue using socket communication without pairing? Finally, I already have the MAC address of my BLE module so I would rather not be scanning. Here is my relevant code:
public class MainActivity extends AppCompatActivity implements Runnable {
private BluetoothAdapter adapter;
private InputStream inputStream;
private OutputStream outputStream;
private Thread thread;
private TextView Status;
private TextView Connection;
private BluetoothSocket socket = null;
public boolean threadStatusInitial; //changed the status global variables to public static
public boolean threadStatus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
threadStatusInitial=true;
threadStatus=true;
Status=(TextView) findViewById(R.id.StatusID);
Connection=(TextView) findViewById(R.id.ConnectionStatus);
adapter= BluetoothAdapter.getDefaultAdapter();
if(adapter==null){
Toast.makeText(this,"bluetooth is unavailable",Toast.LENGTH_SHORT).show();
finish();
return;
}
thread=new Thread(this);
}
public void connect(View view){
BluetoothDevice device=adapter.getRemoteDevice("3C:A3:08:94:C3:11");
try {
socket=device.createRfcommSocketToServiceRecord(device.getUuids()[0].getUuid());
socket.connect();
Connection.setText("Connected");
inputStream=socket.getInputStream();
outputStream=socket.getOutputStream();
if (threadStatusInitial){
thread.start();
threadStatusInitial=false; //this ensures that the thread.start() method will only be called during the initial connection
}
threadStatus=true;
} catch (IOException e) {
Toast.makeText(this,"Can't Connect",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
The thread related global variables have to do with maintaining the logging thread during disconnects and reconnects to the BLE module.
Thanks!
First of all Bluetooth low energy is not meant to use Sockets for connection and data transfer. The whole point of BLE is to keep power consumption as low as possible that cannot be achieved by sockets as they maintain the continue data transfer stream regardless we are sending any data or not.
You can get help from this link for android- HM10 communication.
http://android-er.blogspot.in/2015/12/connect-hm-10-ble-module-to-android.html
Bluetooth classic and Bluetooth Low Energy, although related are different standards. For a classic connection you would use something like the code you have illustrated. But a BLE client is much different. Requires completely different client code. I think your device HM-10 (CC41) BLE module likely only supports BLE. I believe your only choice is to migrate to BLE.
Related
I have an industrial computer running Android v7 with multiple serial outputs, I am trying to send packets using RS232 to my COM3 port (/dev/ttyS2) nevertheless I am unable to open a connection since my serial drivers are not detected.
The cable is well connected and I don't have any issues communicating when running a NodeJS script.
Here is the code used in the Android App
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
/*[...]*/
public static UsbSerialPort usb2SerialEnum(Context context)
{
UsbSerialPort device = null;
// Find all available drivers from attached devices.
UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
if (availableDrivers.isEmpty())
{
return null; // -> availableDrivers is always empty
}
/*[...]*/
}
protected void onCreate(Bundle savedInstanceState)
{
UsbSerialPort port = usb2SerialEnum(this);
if (port != null)
{
/*[...]*/
}
}
I always receive an empty list of available drivers, would you have any idea about what am I doing wrong or what I should try ?
I have been stuck on this issue for quite some time, any help is appreciated, thanks a lot !
I am able to pair devices with the android studio app but I get the tag
"CouldNotConnectToSocket" even though the device is paired.
I am new to android studio so I am really stuck with where to go next.
I also get
getBluetoothService() called with no BluetoothManagerCallback
The UUID I created is:
private final static UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
Can anyone please help me?
new Thread() {
#Override
public void run() {
device = BA.getRemoteDevice(address);
try {
BTSocket = device.createRfcommSocketToServiceRecord(BTMODULEUUID);
//BTSocket = createBluetoothSocket(device);
Log.d(TAG, "Device Connected");
BA.cancelDiscovery();
BTSocket.connect();
} catch (IOException ex) {
Log.d(TAG, "CouldNotConnectToSocket");
closeSocket(BTSocket);
}
}
}.start();
The issue I found out was that the devices I was trying to connect to send data back and forth require Bluetooth Low Energy support from the app.
Is there any way to automatically connect a specific device via Bluetooth LE on app startup?
I've been scrolling through stack overflow for the past few hours and have seen a number of similar questions, although majority are quite outdated and deal with reflections or other complex methods that I can't quite comprehend (these methods I've tried to implement, but not successfully, as I didn't really understand what was going on).
So far, I've managed to find the device by its friendly name, although I have no clue what to execute in that if statement. This is within my MainActivity:
protected void onCreate(Bundle savedInstanceState) {
...
if (bluetoothAdapter == null) {
Toast.makeText(getApplicationContext(),"Bluetooth not supported",Toast.LENGTH_SHORT).show();
} else {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if(pairedDevices.size()>0){
for(BluetoothDevice device: pairedDevices){
if (deviceName.equals(device.getName())) {
//Device found!
//Now how do I pair it?
break;
}
...
Assuming you've successfully identified the BlueToothDevice, you now need to connect to the GATT(Generic Attribute Profile), which allows you to transfer data.
Use the BlueToothDevice.connectGatt method. Using the first overload, the method takes in a Context , a boolean (false = directly connect, true = connect when available), and a BlueToothGhattCallback. The callback receives info from the device.
BlueToothGatt blueToothGatt = device.connectGatt(this, false, blueToothGattCallback);
An example to implement the callback:
BluetoothGattCallback blueToothGattCallback =
new BluetoothGattCallback()
{
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if(newState == BlueToothProfile.STATE_CONNECTED){
/* do stuff */
}
}
}
More details on the callbacks here.
Ended up scrolling through the source code for this app, particularly the SerialSocket, SerialService and SerialListener files which completely solved my problem.
I'm trying to use an Android device to connect to Bluetooth devices to retrieve some information. In particular I'm trying to connect to Bluetooth headphones on this UUID:
"0000111E-0000-1000-8000-00805F9B34FB"
To do this I'm creating a socket and connecting it to the remote device this way:
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothSocket tmp = null;
mmDevice = device;
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createRfcommSocketToServiceRecord(UUID_HF);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it otherwise slows down the connection.
bluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(mmSocket);}
It works fine when the headphones are not yet connected with my Android device. But what happens is that the headphones connect automatically with my Android device thanks to the OS itself. And in this case, when I execute the mmSocket.connect() method, it does not return. I thought that maybe Android has connected automatically another socket with the same UUID and so mine doesn't work. Do you think this is the problem? And if it is, is there a way to close all the sockets between my Android device and a remote Bluetooth device? Or maybe just the one that is bothering my process?
Thanks in advance.
what actually happens is the OS is doing the paired device criteria to save some battery as the searching process consume a lot of energy.
since you've done the search you should go for searching in paired devices not normal search and the result of the search should be taken from
Query paired devices
Before performing device discovery, it's worth querying the set of paired devices to see if the desired device is already known. To do so, call getBondedDevices(). This returns a set of BluetoothDevice objects representing paired devices. For example, you can query all paired devices and get the name and MAC address of each device, as the following code snippet demonstrates:
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
// There are paired devices. Get the name and address of each paired device.
for (BluetoothDevice device : pairedDevices) {
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
To initiate a connection with a Bluetooth device, all that's needed from the associated BluetoothDevice object is the MAC address, which you retrieve by calling getAddress(). You can learn more about creating a connection in the section about Connecting Devices.
this is the official documentation from google covering every detail about Bluetooth:
https://developer.android.com/guide/topics/connectivity/bluetooth
I'm kind of new in this kind of development. To be short I'm working on a android app which sends a string to the cloud (I have a virtual server machine on Amazon), everything works well sending the string from my phone to the server machine, I print the string I'm sending and it works!. But when getting the response back from the server to my android app (I'm running it on my android phone) I don't get anything (The response should be a string + another string concatenated), that's it, easy right? But unfortunately I can't receive it back. I tested the server side and It's working properly (The amazon EC2). I'm not really sure if I can do what Im doing which is:
CREATING ransmission code to send the String by using a SOCKET TO SEND DATA TO THE CLOUD ON THE doInBackground() method from the AsyncTask class.
In the same method doInBackground I do the code to receive the response back by using a ServerSocket to receive the response back from the cloud. Is it possible or do I need another thread or something like that?
Here is my code:
`import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.*;
import android.os.AsyncTask;
import android.view.View;
public class ReadWebpageAsyncTask extends Activity {
private TextView textView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.TextView01);
}
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls)
{
String response = "";
//Transmission
try
{
Socket socket = new Socket("MyAmazonServerIp", 5678);
DataOutputStream salida = new DataOutputStream (socket.getOutputStream());
salida.writeUTF("Llego Perfectamente");
socket.close();
salida.close();
}
catch (Exception e)
{
e.printStackTrace();
}
//Final ends
// Reception
boolean ak=true;
try
{
ServerSocket ServerSock = new ServerSocket(7896);
while(ak)
{
Socket cl=ServerSock.accept();
InetAddress ipC = cl.getInetAddress();
DataInputStream en= new DataInputStream(cl.getInputStream());
response= en.readUTF();
//response= response.toString();
ak=false;
}
}
catch(Exception exp)
{
exp.printStackTrace();
}
// Reception ends
return response;
} //doInBackground ends
#Override
protected void onPostExecute(String result)
{
textView.setText(result);
}
}
public void readWebpage(View view) {
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] { "????" });
}
}`
I will really appreciate any help since I've been working on this for days and I have not been able to solve it.
Thanks,
The way you are doing it can not work over a 3G or likely even a WiFi connection. It can't work over 3G because the address your Amazon server sees is the address of the proxy/firewall on your cell provider's network. No external application can open a socket directly to your phone. Instead you need to send the response back over the same socket the phone created to send the initial message.
Over WiFi, it will not work because of the NAT translation likely going on with your WiFi firewall.
This is done for many reasons, not the least of which is data usage and security. Specifically, think about if your phone was publicly addressable to the entire Internet? It would constantly be getting hit with attempts to hack it.
So basically, just keep the original socket open and listen for a response on that socket and on your cloud server just send the response back over teh same socket you receive the request on.