I have a working Bluetooth server running (Android app). I would like to set a specific Bluetooth port for it to listen to. The reason for that is that for the client to connect, it takes about 10-15 seconds because it needs to first discover the server (i do a scan ).
the code to create the server is the following:
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
UUID my_uuid = UUID.fromString("12345678-f6ff-4f6f-1f1f-f8f8f8fffff8");
try {
BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("myBluetoothServer", my_uuid);
sock1 = serverSocket.accept();
i_s = sock1.getInputStream();
o_s = new OutputStreamWriter(socket.getOutputStream());
new Thread(writter).start();
...
Question: how to specify a fixed port number for the server?
I have been looking here, of course, but it is not easy to find,:
https://developer.android.com/reference/android/bluetooth/BluetoothSocket?hl=ur
I am looking for something like serverSocket.setPort(myPortNumber) (pseudo - code)
The concept of port does not exist for Bluetooth Sockets since they are not regular TCP/IP sockets. They are just abstracted to behave like one.
As you figured out from your code, what you specify is a UUID which is a service identifier. The process to connect to a Bluetooth server goes like this:
Bluetooth Device scan: You can't skip this part, since you need a valid BluetoothDevice object
Service Discovery for a discovered Device: This is the part where you "check" if that Bluetooth Device is running the service that you are looking for (Your service UUID) So you shouldn't skip this part either, unless you want to connect to all surrounding Bluetooth devices.
Related
My understanding is that the SDP is a list of UUIDs that other devices can fetch.
According to this PDF from MIT, "A more general way to think of
SDP is as an information database." Does this mean I can add multiple values to SDP? Since Android has BluetoothDevice.fetchUuidsWithSdp(), how do I set the UUIDs of a device?
Also, what does each section of an UUID mean? UUIDs look like 00000000-0000-1000-8000-00805F9B34FB, but what information does this convey?
An UUID identifies a service that is available on a particular device. So if you call BluetoothDevice.fetchUUidsWithSdp() your BroadcastReceiver will receive the relevant Intent ACTION_UUID containing the device and the service UUID.
The bluetooth specification defines some common UUIDs.
If you don't want to connect to one of these well known services but intent to implement your own bluetooth application, then you have to just generate your own UUID (use uuidgen from a unix console or an online generator) that identifies your application/service.
You can create an UUID instance in java like this UUID uuid = UUID.fromString("785da8ea-1220-11e5-9493-1697f925ec7b");.
So if you create the server side for your bluetooth application on Android you typically do this
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("YourHumanReadableServiceName", uuid);
And this is where you "set" your UUID. The Android bluetooth API creates the SDP-entry consisting of YOUR application's UUID and name for you. Other devices can now retrieve this entry. Androids bluetooth stack will now associate a bluetooth channel to your BluetoothServerSocket. If you want to connect to this ServerSocket, the connecting side usually connects doing this:
// you will most likely already have this instance from a discovery or paired device list
BluetoothDevice serverDevice = adapter.getRemoteDevice(bluetoothMacAddress);
// connect to your ServerSocket using the uuid
BluetoothSocket socket = serverDevice.createRfcommSocketToServiceRecord(uuid);
socket.connect();
Android will again do the heavy lifting for you: It checks the SDP-Records on the remote device, looks up the bluetooth channel that corresponds to your service's UUID and connects using this information.
There is a common code snippet spooking around here on SO that advices you to use "reflection" to get to a hidden API looking similar to this code:
try {
// this is the way to go
socket = device.createRfcommSocketToServiceRecord(uuid);
socket.connect( );
} catch ( IOException exception ) {
// don't do that! You will bypass SDP and things will go sideways.
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
socket = (BluetoothSocket) m.invoke(device, 1);
socket.connect();
}
Most people try this and it "just works" in their dev environment but you should know what you do using this. You actively bypass the SDP lookup that retrieves the right bluetooth channel to be used with your service and you will end up connecting to channel 1. If you have more than one Service running on the device, things WILL go sideways in this cases and you will end up in debugging hell ;-)
I developed a small middleware called Blaubot to create small networks using bluetooth/wifi/nfc and experienced all sorts of problems on the devices I used to test with (12 models). It was often the case that the bluetooth stack was not fully functional anymore in cases where it got some load or after many connects/disconnects (which you usually will have, if you are developing your app). In these cases the device.createRfcommSocketToServiceRecord(uuid) would occasionally fail and only turning the bluetooth adapter off and on again helped to bring the bluetooth adapters back to life (in some cases only after a full power cycle). If this happens and you use the reflection method, you will probably not have much fun with bluetooth.
But if you know this and keep concurrent calls to the BluetoothAdapter within bounds, bluetooth connections and the adapters will be pretty stable.
I am getting bluetooth socket connection problem and so tried various alternatives to connect.
It is like if first fails then second and if second also fails then third and so the main UI blocks during the process.
The exceptions are like -
"Service discovery failed" OR "Host is down"
My all three alternatives -
1) Connect with a connect() function
m = bdDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
socket = (BluetoothSocket) m.invoke(bdDevice, Integer.valueOf(i));
mBluetoothAdapter.cancelDiscovery();
socket.connect();
2) Connect with a accept() function
m = bdDevice.getClass().getMethod ("listenUsingRfcommOn", new Class [] {int.class});
BluetoothServerSocket returnValue =
(BluetoothServerSocket) m.invoke(bdDevice, new Object [] {29});
socket = returnValue.accept();
3) Connect with a well know SPP UUID
private final UUID my_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
socket = bdDevice.createInsecureRfcommSocketToServiceRecord(my_UUID);
mBluetoothAdapter.cancelDiscovery();
socket.connect();
The second alternative is recently added and so I am not sure that how is it different from first and third one. All will block the UI until connect, all can through IOException.
1) You are connecting as a client to your SPP device. Therefore your device must be expecting a connection before you can actually connect.
2) You are accepting the connection as the server. Your bluetooth device will be responsible for firing the connection requests.
3) You are connecting to a device that uses a particular UUID as it's Serial Port Profile (SPP). Think of this as similar to ports in http protocol. The 00001101-0000-1000-8000-00805F9B34FB, is one of the most common ones. More info : https://developer.bluetooth.org/TechnologyOverview/Pages/SPP.aspx
Additionally, if you are thinking on supporting multiple OS / handset versions. You might see those error messages after an initial broken comm. Android's bluetooth stack (bluez) was totally replaced on 4.2, but you might need to still handle previous known bugs.
Reflection in this case is a good thing (some parts of the bluetooth API wasn't public in older versions). But, in my experience, API level < 17; using createInsecureRfcommSocket instead of createRfcommSocket is much more reliable.
Hope this helps. But if you are building an app for a custom bluetooth spp device of yours, explaining how that devices handles comms could help pointing out the exact root of your problem. Although, bluetooth on Android is never straight forward.
I try to develop a simple android app with a ble device.
I found many source code from the Intenet. However, both of them were start from scanning a list of available ble device.
As I have MAC address of the device,UUID of service and characteristic.
How can I connect to the known device and read one specific characteristic directly??
To connect a specific Bluetooth Device which has details like MAC address of the device, UUID of service and characteristic etc. you already know. To do this you need a BluetoothDevice object to make a call like this:
yourBluetoothDevice.connectGatt(getApplicationContext(), false, bleGattCallback);
So for this (yourBluetoothDevice) you have to start the scan at first to get same device object to connect by comparing it's MAC address. However, you got that same device object in onLeScan callback just stop scanning and make a connection with the same device.
Note: Making a connection should be on UIThread(Either using Handler, runOnUIThread or mainlooperThread) otherwise it will give issue in some devices for 'Fail to register callback'
Here yourBluetoothDevice is the device object reference with you want to make a connection.
bleGattCallback is the registered new BluetoothGattCallback() callback for connection status, discovered services, characteristics read and write etc.
Take a look at createInsecureRfcommSocketToServiceRecord. Something like this:
UUID uuid = UUID.fromString("<Your UUID>");
BluetoothSocket socket = yourBLEDevice.createInsecureRfcommSocketToServiceRecord(uuid);
Method m = yourBLEDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
socket = (BluetoothSocket) m.invoke(yourBLEDevice, 1);
If you already know the mac address, you can try something like below:
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mMacAddress);
final BluetoothGatt mGatt = device.connectGatt(getApplication(), false, gattCallback);
I'm starting to work on Bluetooth in Android recently.
I want to build an application that can read the data recorded by a sensor through bluetooth.
I have some sample code, but looks like I need another UUID of a different device.It looks like this:
private static final UUID MY_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
Later on in the code, it uses this UUID to make a connection:
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
I have done some research online, like [here][1]. I think I need a different UUID number for the new device I'm working on. How do I get the UUID number?
On the device, there are two lines of number saying:
SN: 1201L0023
BT: 10:00:E8:C5:16:85
Thanks in advance!
Jake
UUIDs are not tied to particular devices. They identify software services. Some UUIDs for defined profiles are set by BT. The UUIDs used with RFCOMM sockets like your example are arbitrary. You just need both sides to use the same one. In general, devices connect and then use service discovery protocol to find out what services (UUIDs) are supported on the remote device.
I am developing an application which should connect 2 Android devices through Bluetooth automatically. Let's say they are already paired. Is it possible to achieve that?
Of course it is possible. I'll make a short tutorial out of the documentation:
Start with the BluetoothAdapter - it is your Bluetooth manager.
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
If bluetoothAdapter is null, it means that this Android device does not support Bluetooth (It has no Bluetooth radio. Though I think it's rare to encounter these devices...)
Next, make sure Bluetooth is on:
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, request_code_for_enabling_bt);
}
If it's not on, we start the activity which asks the user to enable it.
Let's say the user did enable (I guess you should check if he did, do it in your onActivityResult method). We can query for the paired devices:
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
Then loop over them: for(BluetoothDevice device : pairedDevices) and find the one you want to connect to.
Once you have found a device, create a socket to connect it:
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(YOUR_UUID);
YOUR_UUID is a UUID object containing a special ID of your app. Read about it here.
Now, attempt to connect (The device you are trying to connect to must have a socket created with the same UUID on listening mode):
socket.connect();
connect() blocks your thread until a connection is established, or an error occurs - an exception will be thrown in this case. So you should call connect on a separate thread.
And there! You are connected to another device. Now get the input and output streams:
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
and you can begin sending/receiving data. Keep in mind that both actions (sending and receiving) are blocking so you should call these from separate threads.
Read more about this, and find out how to create the server (Here we've created a client) in the Bluetooth documentation.