How to connect pybluez RFCOMM server socket on Debian? - android

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?

Related

Android Bluetooth RFCOMM directly to Raspberry Pi without pairing

I need to make an application that communicates through an RFCOMM socket to a Raspberry Pi, without pairing.
On the Android side, I have the MAC address of the RPi and I'm trying to connect to the server using this code:
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
BluetoothSocket mmSocket = null;
try {
mmSocket = device.createRfcommSocketToServiceRecord(UUID);
mmSocket.connect();
Log.d(TAG, "mmSocket returned");
}
...
UUID is the same as on the server-side, and i've also tried using the createInsecureRfcommSocket method.
On the Raspberry Pi side, I used the pybluez example of an rfcomm server(here is the example)
It once worked but I don't understand why it did or why it doesn't anymore, in the sense that when I tried to initiate the connection from the phone I got a pairing request on the Raspberry Pi without a pairing request on the phone, and the socket object on android had successfully connected.
Does anyone know what I am doing wrong, or any ideas that might help me, and is such a thing even feasible.
Thanks in advance.
I've found this unanswered question and I think I have a working solution at least for my case.
All I needed to do was to call these three commands:
sudo hciconfig hci0 piscan
sudo hciconfig hci0 sspmode 1
sudo hciconfig hci0 class 0x400100
The first two lines make the RPi discoverable, from this answer, which also claims the RPi should pair automatically. That does NOT work for me. It still requires PIN confirmation on both devices, that's unfortunate for a headless RPi.
The third line found in this answer is crucial and it is what allows to connect RFCOMM sockets to unpaired RPi.
It is possible that changing class will make other BT services stop working, not sure, I just need RFCOMM.
After this, the following example works for me with RPI 4B and my Win10 laptop:
import socket
from contextlib import closing
# MAC address of RPi, can be obtained with `bluetoothctl list` on RPi.
rpi_addr = 'e4:5f:01:7d:8A:A3'
# 1-32, some might be used already, e.g. 3 for me, in that case bind fails.
channel = 15
def server():
print("Creating socket")
with closing(socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM,
socket.BTPROTO_RFCOMM)) as s:
print("Binding socket")
s.bind((rpi_addr ,channel))
print("Listening socket")
s.listen()
s_sock, addr = s.accept()
with closing(s_sock):
print ("Accepted connection from "+str(addr))
data = s_sock.send(b"Hello from RPi")
def client():
print("Creating socket")
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM,
socket.BTPROTO_RFCOMM)
print("Connecting socket")
s.connect((rpi_addr,channel))
print("Connected")
data = s.recv(1024)
print(f"Received {data}")

Receiving messages over bluetooth to raspberrypi

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!

Send AT-command through bluetooth with python

I try to send AT commands from my computer (ubuntu 13.04) to my phone (Android 5.1) via bluetooth. I want to read the SMS.
I retrieve the MAC address of my phone with :
hcitool scan
I browse all available services on the device with :
sdptool browse XX:XX:XX:XX:XX:XX
I get the good RFCOMM channel for SMS/MMS service and now I'm trying to send the AT command.
I tried with pySerial with a bound and connected rfcomm to my phone but no response :
import serial
phone = serial.Serial('/dev/rfcomm0', 115200, timeout=2)
phone.write(b'AT\r')
data = phone.readall()
print data
I tried the same code on a USB serial port and I have a response :
import serial
phone = serial.Serial('/dev/ttyACM0', 115200, timeout=2)
phone.write(b'AT\r')
data = phone.readall()
print data
# *EMRDY: 1
# AT
# OK
I tried with pyBluez but same problem, no response of my AT command :
import bluetooth
client_sock = bluetooth.BluetoothSocket( bluetooth.RFCOMM )
client_sock.connect(('XX:XX:XX:XX:XX:XX', 4))
client_sock.send(b'AT\r')
data = client_sock.recv(1024)
print "received [%s]" % data
And I finally tried with native python sockets, but no response :
import socket
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
s.connect(('XX:XX:XX:XX:XX:XX',4))
s.send(b'AT\r')
data = s.recv(1024)
s.close()
print('Received', repr(data))
Note: The phone displays a prompt window to accept that my computer accesses my sms. Of course I accepted.
Can anyone tell me what is wrong and what I can try?
Well, for starter it is better to check first that you have a two-way communication between your Host computer and your Phone on bluetooth, like you said, it did work with USB, then there should be no reason it does not with bluetooth unless you didn't yet established a good communication, so I think it is better to try first that you have good communication by just sending and replying with the same string (kinda hand-shaking protocol) and make sure that you know what your python code is actually sending, may be unseen extra characters using bluetooth that you don't pay attention to, which makes your AT command unrecognizable by your phone.

Is it possible to establish a Bluetooth connection with a Java/Android client and Python server?

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()

Bluetooth connection between Android and Linux (RPi) lost on first write action

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.

Categories

Resources