So I have been working on a project in which a device running Android (API level = 14) must connect to a server running Linux (to be specific: a Raspberry Pi) via Bluetooth. When a connection is established, the app sends an encrypted XML string to the RPi. The RPi must decrypt this string, parse the XML and perform the corresponding action. The result of the action is send back to the Android device.
So far, I have managed to create a connection between the app and the RPi (which runs the latest version of the Bluez package). The RPi has a Bluetooth 4.0 dongle from Targus. The point where I'm stuck at, is when I try to send a string from the app to the RPi. The Bluetooth socket appears to be closed by then. Logcat gives the message Connection reset by peer.
The code used to create the socket is as follows:
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(device, 1);
Logcat output is as follows:
06-20 14:29:42.224: DEBUG/RPiService(24273): ---------- [ CONNECTION ESTABLISHED ] ----------
06-20 14:29:42.224: DEBUG/RPiService(24273): connected, Socket Type:Secure
06-20 14:29:42.229: DEBUG/RPiService(24273): create ConnectedThread: Secure
06-20 14:29:43.734: DEBUG/RPiService(24273): setState() 2 -> 3
06-20 14:29:43.739: DEBUG/RPiService(24273): Connection reset by peer
06-20 14:29:43.744: WARN/System.err(24273): java.io.IOException: Connection reset by peer
06-20 14:29:43.754: WARN/System.err(24273): at android.bluetooth.BluetoothSocket.writeNative(Native Method)
06-20 14:29:43.759: WARN/System.err(24273): at android.bluetooth.BluetoothSocket.write(BluetoothSocket.java:398)
06-20 14:29:43.764: WARN/System.err(24273): at android.bluetooth.BluetoothOutputStream.write(BluetoothOutputStream.java:85)
06-20 14:29:43.769: WARN/System.err(24273): at com.example.BluetoothTest.RPiService$ConnectedThread.run(RPiService.java:344)
On the side of the RPi, I am essentially running the following example server script from the PyBluez package:
from bluetooth import *
server_sock=BluetoothSocket( RFCOMM )
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port = server_sock.getsockname()[1]
uuid = "00001101-0000-1000-8000-00805F9B34FB"
advertise_service( server_sock, "SampleServer",
service_id = uuid,
service_classes = [ uuid, SERIAL_PORT_CLASS ],
profiles = [ SERIAL_PORT_PROFILE ]
)
print "Waiting for connection on RFCOMM channel %d" % port
client_sock, client_info = server_sock.accept()
print "Accepted connection from ", client_info
try:
while True:
data = client_sock.recv(1024)
if len(data) == 0: break
print "received [%s]" % data
except IOError:
pass
print "disconnected"
client_sock.close()
server_sock.close()
print "all done"
I've tried various UUIDs suggested by posts I read on SO including 00001101-0000-1000-8000-00805F9B34FB, 94f39d29-7d6d-437d-973b-fba39e49d4ee and 00000003-0000-1000-8000-00805F9B34FB (always the same on both ends of the connection). It appears to be that the first one is correct as I can't even make a connection when using an other UUID.
What may be the cause for the connection to be reset by the RPi? If anyone would be able to point me in the right direction, I'd be grateful.
It turned out that the default Bluez configuration on Debian was the cause of the connection issues (as described in this answer. Disabling the pnat plugin in /etc/bluetooth/main.conf allowed for communication between Android and the RPi.
DisablePlugins = pnat
For future reference, the UUID used by the applications is 00000003-0000-1000-8000-00805F9B34FB.
Related
Modern programming is turning more and more frustrating. Trying to do a simple socket test app on Flutter (tested on Android). Code is simple and self explanatory:
void Connect()
{
print("connecting...");
Socket.connect("localhost", 80).then((Socket sock) {
socket = sock;
socket?.listen(dataHandler,
onError: errorHandler,
onDone: doneHandler,
cancelOnError: false);
socket?.write("GET / HTTP/1.1");
}).catchError((Object e) {
print("Unable to connect: $e");
});
}
Code throws exception. Output:
I/flutter (15930): connecting...
I/flutter (15930): Unable to connect: SocketException: OS Error: Connection refused, errno = 111, address = localhost, port = 47244
The port is always different, why TF is that happening?
The port number in the error message is the local port and not the remote port. There are an issue about this problem here: https://github.com/dart-lang/sdk/issues/12693
In short, when connecting using TCP, you need two ports. One local which is open on your device and one remote which is the port open on the system you are trying to call. After a connection is established, the communication is going between this two port numbers.
So the error indicates that your server running on localhost:80 is refusing the connection from your application. The local port number in the error message can often just be ignored since it is not really relevant to debug most issues.
I would like to receive the messages from my phone to raspberry over bluetooth
I have written the following code ,
import bluetooth
hostMACAddress = '18:9E:FC:A1:81:93' # The MAC address of my iphone
port = 3
backlog = 1
size = 1024
s = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
s.bind((hostMACAddress, port))
s.listen(backlog)
try:
client, clientInfo = s.accept()
while 1:
data = client.recv(size)
if data:
print(data)
client.send(data) # Echo back to client
except:
print("Closing socket")
client.close()
s.close()
How can i receive the messages to my Raspberry when i run this code, i see no messages being received, my raspberry detects the MAC address of my iPhone but i would like to send some message and see if the bluetooth of raspberry can receive it
Kindly let me know what modifications i have to do in this code in order to achieve bluetooth connection
I haven't completed building an app using Flutter but I have the server/client code ready using python.
Server.py
import socket
import os
import multiprocessing
from multiprocessing import pool
os.system('sudo python3 relay.py C') #runs relay program and setups up GPIO pins
hostMACAddress = 'B8:27:EB:A3:B6:EB' # The MAC address of a Bluetooth adapter on the server.
backlog = 4
port=3
size = 1024
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
s.bind((hostMACAddress,port))
s.listen(backlog)
def new_client(client):
while 1:
data = client.recv(size)
if data:
n=data.decode("utf-8")
if n == 'ON':
os.system('sudo python3 relay.py ON')
if n == 'OFF':
os.system('sudo python3 relay.py OFF')
if n == 'CLOSE':
break
client.send(data)
if __name__ == '__main__':
client, address = s.accept()
pool = multiprocessing.Pool(4)
pool.map(new_client, (client, ))
pool.close()
pool.join
print("Closing socket")
client.close()
s.close()
This is my server program running on raspberry pi.
I implemented multithreading to allow 4 active connections(sockets) at all time, since bluetooth is a little different than web socket programming I had to get creative to keep the application running after any client closes connection.
Basically if I get the message ON/OFF, it in turn runs another python program that turn the relay on or off, if I get CLOSE message, I terminate the thread.
Client.py
import bluetooth
bd_addr = 'B8:27:EB:A3:B6:EB'
port = 3
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((bd_addr,port))
print("Connected")
while True:
try:
data = input()
sock.send(data.encode())
if data == 'CLOSE':
break
except KeyboardInterrupt:
sock.close()
This is my client program running on my computer.
Notice the address in both codes in the same(MAC Address of my raspberry pi), because raspberry pi need the address of the bluetooth adapter to use(in case some machines have multiple interfaces) and client needs server bluetooth MAC Address in order to initiate socket connection. You also need to port that you configured in raspbery pi to receive connection in my case 3.
Let me know if you need any additional information.
Have fun making an app that implements socket programming!
I am trying to make a bluetooth connection with my Android client and a Python server. However, I am unable to do so since my Android client always fails to connect. Now I am wondering whether it is possible at all to use an Android Bluetooth socket and a python socket together. Is that possible?
And if so, do you have suggestions what else I might try? In a nutshell, this is what I do:
My Android client:
I get a Bluetooth device like this:
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().
getRemoteDevice(deviceAddress);
Where deviceAddress is equal to the bluetooth MAC address of my laptops bluetooth adapter. Which is E0:F8:47:3F:80:49
Then I use that device to create a Socket:
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(MY_UUID);
Where MY_UUID is this string: 00001101-0000-1000-8000-00805F9B34FB
After that I just call connect:
socket.connect();
And that is where it fails to connect. Maybe it is because of server wihich looks like this:
My Python server:
import bluetooth
hostMACAddress = 'E0:F8:47:3F:80:49' # The MAC address of a Bluetooth adapter
port = 3
backlog = 1
size = 1024
s = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
s.bind((hostMACAddress, port))
s.listen(backlog)
try:
client, clientInfo = s.accept()
while 1:
data = client.recv(size)
if data:
print(data)
client.send(data) # Echo back to client
except:
print("Closing socket")
client.close()
s.close()
I have these snippet in python with pybluez framework:
from bluetooth import *
server_sock=BluetoothSocket( RFCOMM )
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port = server_sock.getsockname()[1]
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
advertise_service( server_sock, "SampleServer",
service_id = uuid
# service_classes = [ uuid, SERIAL_PORT_CLASS ],
# profiles = [ SERIAL_PORT_PROFILE ],
# protocols = [ RFCOMM_UUID ]
)
print "Waiting for connection on RFCOMM channel %d" % port
client_sock, client_info = server_sock.accept()
print "Accepted connection from ", client_info
try:
while True:
data = client_sock.recv(1024)
if len(data) == 0: break
print "received [%s]" % data
except IOError:
pass
print "disconnected"
client_sock.close()
server_sock.close()
print "all done"
and also I have this other snippet in Android to connect the pybluez rfcomm server socket:
private static final UUID MY_UUID = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee");
....
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(myServerMacAddress);
....
BluetoothSocket tmp= device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
My problem is that Android device could not connect to the pybluez socket.
I think that the way I use to connect is wrong, and I don't know how to connect correctly or advertise my server socket
I offered a bounty, but found the solution myself. :) Posted on another answer but this may also apply to your problem. On certain versions of Debian (Raspbian etc) and maybe some others distros. The server_sock.accept() will by default just hang and never accept a connection - even from a paired device! I'm in some cases even convinced the socket isn't open at all. However, a solution to this is really simple.
Update your /etc/bluetooth/main.conf file, add a line or change the existing so it looks like this:
DisablePlugins = pnat
Then restart the Bluetooth service:
sudo invoke –rc.d bluetooth restart
It now MAY have been fixed.
Good luck!
Reference: RFCOMM without pairing using PyBluez on Debian?
I use this code
luugiathuy.com/2011/02/android-java-bluetooth/
The server side is the PC
the client is the device, with the app based on bluetooth chat example
The device (galaxy tab 7.0) can establish connection with the PC.
However the PC server (written in java and bluecove) did nothing, as nothing is connected.
The loop for trying to find connected device is
while(true) {
try {
System.out.println("waiting for connection...");
connection = notifier.acceptAndOpen();
Thread processThread = new Thread(new ProcessConnectionThread(connection));
processThread.start();
} catch (Exception e) {
e.printStackTrace();
return;
}
Output on PC:
uuid: 0000110100001000800000805f9b34fb
waiting for connection...
EDIT: source downloadhttps://github.com/luugiathuy/Remote-Bluetooth-Android
Same issue I got when I was trying in linux. But the reason (still not sure) when you run the bluetooth android application without turning on the Java server using bluecove, It will try to connect with the already installed bluetooth software. You may see the bluetooth icon asking for granting access to the mobile device.
To solve this, I just changed the uuid in the server and application (say from 1103 to 1101 and vice versa) and then started the server first and then the android application. Java server part started listening.
The reason I think may be the uuid when it did not found the bluecove stack service server, it got connected to the device server listening on same uuid. So after changing the uuid and making sure that the server is running before launching the android application should solve the issue.
If you are getting connected to the bluetooth system application and not to the Java bluecove server,
1) First change the uuid both server and android application.
2) Second make sure your server is running and listening on same uuid.
3) Launch the android application which try to communicate on same rfcomm connection uuid.
Server part code I took from : http://www.jsr82.com/jsr-82-sample-spp-server-and-client/
Library : http://code.google.com/p/bluecove/downloads/list
Yes, it happens with me too, I suggest you to fire following commend on shell, when it shows waiting for connection.
hcitool cc 58:C3:8B:D7:FA:F4
here 58:C3:8B:D7:FA:F4 is my device's bluetooth address, which should be replaced by your device's bluetooth address.
To get your device's bluetooth address, just start bluetooth in your device with discoverable mode and execute hcitool scan command, it will display all the active device with their name and bluetooth address.
Well you may run the above hcitool cc 58:C3:8B:D7:FA:F4 command via Java code as follows,
try
{
Process p=Runtime.getRuntime().exec("hcitool cc 58:C3:8B:D7:FA:F4");
}
catch ( Exception e )
{
}
The output from your program says it listens on UUID 0x1101. Is that true? The sample you reference shows it listening on a different UUID. Its Service Class Id is 0x04c6093b and is set as follows:
34 UUID uuid = new UUID(80087355); // "04c6093b-0000-1000-8000-00805f9b34fb"
35 String url = "btspp://localhost:" + uuid.toString() + ";name=RemoteBluetooth";
36 notifier = (StreamConnectionNotifier)Connector.open(url);
The two need to match on client and server.