So, I've been wanting to make my own raspberry-pi bluetooth speaker that I can connect my android phone to and play music. To do this, I stumbled across the PyBluez library in python, and found that I could use it to create and advertise a bluetooth service. So for testing out to see if I could advertise a service and connect my phone to it, I wrote the following code to try it out:
from bluetooth import *
server = BluetoothSocket(RFCOMM)
server.bind(("", PORT_ANY))
server.listen(1)
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
advertise_service(sock=server, name="Bluetooth Speaker", service_id=uuid, service_classes=[SERIAL_PORT_CLASS], profiles=[SERIAL_PORT_PROFILE])
while True:
client,addr = server.accept()
print "Connection from " + addr
client.close()
However, while the service does show up my phone just doesn't want to connect to it. After some googling, I've already done all of the following steps towards solving this problem, but to no avail:
"DisablePlugins = pnat" in /etc/bluetooth/main.conf
Service bluetooth restart
hciconfig hci0 up
hciconfig hci0 sspmode 0
hciconfig hci0 piscan
sdptool add SP
Is there something else that I need to do in order to get my phone to connect properly to my raspberry pi? Or is there a step that I'm missing?
Thank you!
if it's what i'm thinking you could try putting this in the terminal pulseaudio --start
Might be what you're looking for.
more info here https://www.raspberrypi.org/magpi/bluetooth-audio-raspberry-pi-3/
Related
So this the first time I work with wifi-direct, I am trying to connect my android phone to a raspberry pi zero w over wifi-direct.
using this sample app on my android phone: https://github.com/ahmontero/wifi-direct-demo
I am able to get to the Connected state at the pi in the wpa_cli interface
and on the phone under the device name i see "connected" behind the progressDialog box that says "Connecting to 1e:67:58:4c:78:92" which should be dismissed after connecting but it isn't since WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION isn't being triggered after connecting.
my wpa_supplicant.conf:
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=LB
ap_scan=1
device_name=raspberry
device_type=1-0050F204-1
driver_param=use_p2p_group_interface=1
p2p_go_intent=7
p2p_go_ht40=1
p2p_listen_reg_class=81
p2p_listen_channel=1
p2p_oper_reg_class=81
p2p_oper_channel=1
and have done the following:
on the Pi:
$sudo wpa_supplicant -B -dd -iwlan0 -Dnl80211 -c /etc/wpa_supplicant/wpa_supplicant.conf
$sudo wpa_cli p2p-dev-wlan0
p2p_group_add
OK
<3>P2P-GROUP-STARTED p2p-wlan0-0 GO ssid="DIRECT-VC" freq=2412 passphrase="JrLfUAJf" go_dev_addr=5a:d3:65:e8:fc:e7
wps_pbc
OK
<3>P2P-DEVICE-FOUND 1e:67:58:4c:78:92 p2p_dev_addr=1e:67:58:4c:78:92 pri_dev_type=10-0050F204-5 name='HUAWEI' config_methods=0x188 dev_capab=0x25 group_capab=0x0 wfd_dev_info=0x00101c440032 new=1
<3>P2P-PROV-DISC-PBC-REQ 1e:67:58:4c:78:92 p2p_dev_addr=1e:67:58:4c:78:92 pri_dev_type=10-0050F204-5 name='HUAWEI' config_methods=0x188 dev_capab=0x25 group_capab=0x0
On the Phone:
I run the wifi direct sample app from google
and i can see the device with its info and when i click on connect i get stuck at connecting progressDialog and cant get passed that point to connected mode eventhough i see "connected" under device name.
the app seems to work fine between two phones but with a pi
this line in WiFiDirectBroadcastReceiver.java doesn't get executed when a connection has been made with the pi
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action))
however, when connection is lost after a timeout for example it gets triggered!
my question is what am i doing wrong here, why isn't the WIFI_P2P_CONNECTION_CHANGED_ACTION being detected by the broadcast receiver?
Note: phone is running Android 7.1
compileSdkVersion 26
targetSdkVersion 26
edit:
As Ben has pointed out in his answer below that I need to have a DHCP server running on the GO device (PI in my case), so I went ahead and installed and configured DHCP service on the pi by following the first section at this link https://www.raspberrypi.org/documentation/configuration/wireless/access-point.md
but, I can no longer run sudo wpa_supplicant -B -dd -iwlan0 -Dnl80211 -c /etc/wpa_supplicant/wpa_supplicant.conf command successfully as it might be clashing with the dhcp conf? any idea how i can enable p2p while running DHCP?
Well,
So as a part of GDPR (EU) implementation and similar things.
From android 8 & onwards there will be a restriction on the way by which android devices receive broadcast on any event (ofcourse to hide few device specific infos/specs.)
Please have a look at this:
https://developer.android.com/guide/components/broadcasts
Cheers.
Your Raspberry Pi is in the GO role and needs to act as a DHCP server. An Android device in the Client role will not broadcast WIFI_P2P_CONNECTION_CHANGED_ACTION until it has received an IP address from the GO via DHCP.
See my answer here for further details.
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}")
I just got started with Raspberry pi and I wanted to make a program on my Raspberry which gets input from an app on my Android/iOS device over bluetooth. I wanted to first check if something like this is possible and second if you have any clues on how to do something like this.
Thanks
PS: Since I just got started I'm only looking for clues and I don't want anyone to write and app for me so don't down vote
You would likely need to establish a network communication between the Raspberry Pi and the device.
For the server:
import socket
HOST = '' # This should receive from all available interfaces.
PORT = 1111 # Random port number.
data = "Test" # Data to send to the client.
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((HOST, PORT))
while True:
s.sendto(data, (HOST, PORT))
print data
On the client, very similar code but add:
data, addr = s.recvfrom(1024)
print addr
print "Message received: ", data
Under the while True
Reference the following for setting up RPI wireless hotspot:
http://elinux.org/RPI-Wireless-Hotspot
The HOST for each is going to be the device IPv4 address, usually in format:
192.168.x.x.
I have not personally found a way without using serials for data communication. The most common way to communicate information between devices is over network. Look into peer-to-peer network solutions.
The code may not work as is, you will need to make client/server-side code specific for your needs.
Reference the following for setting up sockets and a low-level network interface: https://docs.python.org/2/howto/sockets.html
Hopefully this helps.
EDIT:
There is a Bluetooth method for RPI.
Here's a good branch in Github that contains example of the Bluetooth library used in Python:
https://github.com/karulis/pybluez/blob/master/examples/simple
Good references:
Bluetooth programming with Python.
http://people.csail.mit.edu/albert/bluez-intro/c212.html
How to create a Bluetooth tag with RPI.
https://www.raspberrypi.org/magpi/create-a-raspberry-pi-3-bluetooth-tag/
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.
I am trying to make a way to telnet to an unrooted Droid. I have the INTERNET permission active, I have my device connected on the same network as my Mac OS X box via WiFi, and I am able to ping the port I opened.
In initial experiments, I got it to work on a rooted test device, but I had the socket handlers run on the UI Thread rather than a separate thread. Now that I have the network modules on a separate thread, I can't get ServerSocket.accept () to return. It works on Google's version of android (vanilla), but not on Samsung's or Sony-Ericsson's.
When I telnet to it, my attempt would time out, and logcat wouldn't print out any exceptions or errors.
Here is a link to a google-code repo of my code: Google-code Repository
I am running ServerScoket.accept () on a separate thread, and run the stream processors on another thread as well. Comments on my design (i.e. I should use Handlers or AsyncTasks) are extremely welcome. Right now, in order to Toast the messages received via telnet, I use a Handler with the looper being acquired via a Context.
The following is what I get when I run netstat -n on the adb shell on the non-working devices:
~$ adb shell netstat -n
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:7777 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:7203 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:47609 127.0.0.1:7777 ESTABLISHED
tcp 0 0 127.0.0.1:7777 127.0.0.1:47609 ESTABLISHED
tcp 0 0 127.0.0.1:47610 127.0.0.1:7777 ESTABLISHED
tcp 0 0 127.0.0.1:7777 127.0.0.1:47610 ESTABLISHED
The difference is that in the working devices, they list an IP with my port open in the state, LISTEN.
UPDATE: Having the <uses-permission android:name="INTERNET"/> set in my android_manifest, I tried changing the port number to 689. It didn't work; I got a BindException, saying that I may be lacking the INTERNET permission. So, I changed it to 1989, and I went back to everything working until accept (). I assume this is because I ran it on a non-root phone, and I don't have access to ports 1024 and below.
UPDATE: I ran a really similar program on my Mac, and it worked fine when I tried telnetting to my Mac using the IP address assigned to me. It didn't work when I tried telnetting from another Mac but it didn't seem to connect; the connection would timeout. It did work over an ad-hoc network, though. I still have yet to try it using the droid, but I will update this asap.
UPDATE: I managed to get the app working on 3 separate Droids running Vanilla (Android released by google). It worked on a Nexus, an Apanda A60 (my first device; adb has ceased to detect it for some reason.), and a custom-made, unbranded tablet. Still, because I already offered a pretty big bounty, I plan on seeing this through to the end.
As stated earlier, my app works with Vanilla versions of android, but not with modified versions. The three phones that failed to run it were all mid-range models; 2 Samsung GT-i5503s, and a Sony-Ericcson E16i.
It seems like you have a networking issue, rather than a code issue. I used your latest project and it is listening on the port, as expected.
I added this to TelnetServer.setupServerSocket() to confirm some information:
Log.i("TelnetServer", "ServerSocket Address: " + this.server.getLocalSocketAddress());
try {
Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
while (en.hasMoreElements()) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
Log.i("TelnetServer", "Listen On: " + inetAddress.getHostAddress());
}
}
} catch (SocketException ex) {
Log.e("TelnetServer", ex.toString(), ex);
}
This will print all of the addresses your service is listening on (if it is listening on 0.0.0.0/0.0.0.0:xxx (printed after ServerSocket Address:)).
You should run emulator with the -tcpdump <file> option and also provide this. It will confirm any connection is being attempted. My hunch is that your client is not able to access the server, which is why the server is not receiving the connection - rather than an issue with the code.
Please provide the tcpdump file, your IP Address (of the client) and the logcat output (including the ServerSocket Address and Listen On statements) for further analysis.
See if netstat -n from the adb shell shows anything actually listening on the port you chose at the time when accept() is not returning.
Also realize that when not running as root, you can only bind unprivileged ports, of which the default telnet port is not an example. Does your code check that bind() was successful?
UPDATE:
Since the code works on a number of devices (where netstat -n would presumably list the socket) the failure to list it on the subject device should probably remain a focus. The Java ServerSocket methods depend on a socket factory which can be over-ridden to let you do distinct calls to socket(), bind(), and listen() specifying fuller details, so it may make sense to try your code that way. There's another case floating around where a device's attempt to support ipv6 seems to be causing someone similar problems, and at least on other java platforms creating the socket at a lower level to specify ipv4 seems like a promising answer.
I understand you have tried most of the things are you are just few steps from getting it right on two particular devices.
Just a thought, If not point to point, why not Use Muti-casting for service registration and discovery in local area networks.
This is the java implementation JmDNS
and this is its Android demo
EDIT : Rather I should say to check connectivity with that two devices.