I've been trying to get a simple python bluetooth example running on my lenovo y50-70 laptop running ubuntu 18. But while doing this i noticed that the Pybluez library is unable to find any devices, while using the bluetoothctl tool can.
import bluetooth
print("performing inquiry...")
nearby_devices = bluetooth.discover_devices(duration=8,
lookup_names=True, flush_cache=True, lookup_class=False)
print("found %d devices" % len(nearby_devices))
for addr, name in nearby_devices:
try:
print(" %s - %s" % (addr, name))
except UnicodeEncodeError:
print(" %s - %s" % (addr, name.encode('utf-8', 'replace')))
Running the code above gives as an output: found 0 devices. While running bluetoothctl gives me the following output:
[NEW] Controller 40:B8:9A:44:E0:46 daan-Lenovo-Y50-70 [default]
Agent registered
[bluetooth]# scan on
Discovery started
[CHG] Controller 40:B8:9A:44:E0:46 Discovering: yes
[NEW] Device 30:AE:A4:37:A2:4A 30-AE-A4-37-A2-4A
[NEW] Device D0:D2:B0:91:1C:C5 D0-D2-B0-91-1C-C5
[NEW] Device 70:73:CB:DF:1B:08 70-73-CB-DF-1B-08
[NEW] Device 51:80:89:6F:6E:B6 51-80-89-6F-6E-B6
[bluetooth]#
I have tried running my python script as root, and my current pybluez version is 0.22. I hope anyone knows how to resolve this issue.
Related
I'm trying to learn to communicate with a Bluetooth device using Python but my first steps fail.
I can successfully connect to a given device using bluetoothctl:
[bluetooth]# connect F5:EE:1C:40:21:44
Attempting to connect to F5:EE:1C:40:21:44
[CHG] Device F5:EE:1C:40:21:44 Connected: yes
Connection successful
[NEW] Primary Service (Handle 0xa9bd)
/org/bluez/hci0/dev_F5_EE_1C_40_21_44/service000a
00001801-0000-1000-8000-00805f9b34fb
Generic Attribute Profile
[NEW] Primary Service (Handle 0xa9bd)
/org/bluez/hci0/dev_F5_EE_1C_40_21_44/service000b
53300001-0023-4bd4-bbd5-a6920e4c5653
Vendor specific
[NEW] Characteristic (Handle 0x6f54)
/org/bluez/hci0/dev_F5_EE_1C_40_21_44/service000b/char000c
53300002-0023-4bd4-bbd5-a6920e4c5653
Vendor specific
[NEW] Characteristic (Handle 0x6604)
/org/bluez/hci0/dev_F5_EE_1C_40_21_44/service000b/char000e
53300003-0023-4bd4-bbd5-a6920e4c5653
Vendor specific
[NEW] Descriptor (Handle 0x0164)
/org/bluez/hci0/dev_F5_EE_1C_40_21_44/service000b/char000e/desc0010
00002902-0000-1000-8000-00805f9b34fb
Client Characteristic Configuration
but trying to connect via Python3's pybluez module results in an exception being raised:
sock=bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect(("F5:EE:1C:40:21:44", 1))
...
BluetoothError Traceback (most recent call last)
<ipython-input-17-2af54455681d> in <module>
----> 1 sock.connect(("F5:EE:1C:40:21:44", 1))
~/.local/lib/python3.9/site-packages/bluetooth/bluez.py in connect(self, *args, **kwargs)
BluetoothError: [Errno 112] Host is down
What am I doing wrong here? Very likely I'm just missing the very basics of Bluetooth development - maybe you can give me a direction..
Looking at the log information you shared from when you connected with bluetoothctl, it looks like you are connecting to a Bluetooth Low Energy (BLE) device.
The commands you are you issuing with PyBlueZ is to connect to a Bluetooth Classic (BR/EDR) device and I suspect that is why the device is not responding.
PyBlueZ uses a deprecated API for BlueZ. The currently supported APIs are documented at:
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc
It is the Device API that is used for connecting to a device. Below is an example of how to use it with the generic D-Bus library pydbus
from time import sleep
import pydbus
DEVICE_ADDR = 'F5:EE:1C:40:21:44' # device address
# DBus object paths
BLUEZ_SERVICE = 'org.bluez'
device_path = f"/org/bluez/hci0/dev_{DEVICE_ADDR.replace(':', '_')}"
# setup dbus
bus = pydbus.SystemBus()
device = bus.get(BLUEZ_SERVICE, device_path)
# Connect to device
device.Connect()
sleep(10)
device.Disconnect()
First off if anybody knows of a good tutorial for coding bluetooth on my raspberry pi zero w with python to turn on discovery, listen for a pair request, connect and save the paired device, and more, that would be awesome. My code for testing bluetooth discovery is below.
import bluetooth
print("performing inquiry...")
nearby_devices = bluetooth.discover_devices(
duration=8, lookup_names=True, flush_cache=True)
print("found %d devices" % len(nearby_devices))
for addr, name in nearby_devices:
try:
print(" %s - %s" % (addr, name))
except UnicodeEncodeError:
print(" %s - %s" % (addr, name.encode('utf-8', 'replace')))
The TraceBack is below
Traceback (most recent call last):
File "bluetoothConnect.py", line 6, in <module>
duration=8, lookup_names=True, flush_cache=True)
File "/usr/lib/python2.7/dist-packages/bluetooth/bluez.py", line 17, in discover_devices
sock = _gethcisock ()
File "/usr/lib/python2.7/dist-packages/bluetooth/bluez.py", line 226, in _gethcisock
raise BluetoothError ("error accessing bluetooth device")
bluetooth.btcommon.BluetoothError: error accessing bluetooth device
("error accessing bluetooth device") is the clue.
Yes - as earlier mentioned you need elevated privileges.
Simply run the script with sudo...
eg - sudo python myscript.py
enter your password
It should now work..for testing purposes.
Though going forward I would create a privileged user and add that user to the root group with the setting /bin/false.
Then use that user to run all your scripts..
Had the same issue and then I wrote this simple script to wrap Bluetoothctl using python3. Tested on Raspberry pi 4.
import subprocess
import time
def scan(scan_timeout=20):
""" scan
Scan for devices
Parameters
----------
scan_timeout : int
Timeout to run the scan
Returns
----------
devices : dict
set of discovered devices as MAC:Name pairs
"""
p = subprocess.Popen(["bluetoothctl", "scan", "on"])
time.sleep(scan_timeout)
p.terminate()
return __devices()
def __devices():
""" devices
List discovered devices
Returns
----------
devices : dict
set of discovered devices as MAC:Name pairs
"""
devices_s = subprocess.check_output("bluetoothctl devices", shell=True).decode().split("\n")[:-1]
devices = {}
for each in devices_s:
devices[each[7:24]] = each[25:]
return devices
def info():
""" Info
Returns
----------
info : str
information about the device connected currently if any
"""
return subprocess.check_output("bluetoothctl info", shell=True).decode()
def pair(mac_address):
""" pair
Pair with a device
Parameters
----------
mac_address : str
mac address of the device tha you need to pair
"""
subprocess.check_output("bluetoothctl pair {}".format(mac_address), shell=True)
def remove(mac_address):
""" remove
Remove a connected(paired) device
Parameters
----------
mac_address : str
mac address of the device tha you need to remove
"""
subprocess.check_output("bluetoothctl remove {}".format(mac_address), shell=True)
def connect(mac_address):
""" connect
Connect to a device
Parameters
----------
mac_address : str
mac address of the device tha you need to connect
"""
subprocess.check_output("bluetoothctl connect {}".format(mac_address), shell=True)
def disconnect():
""" disconnect
Disconnects for currently connected device
"""
subprocess.check_output("bluetoothctl disconnect", shell=True)
def paired_devices():
""" paired_devices
Return a list of paired devices
"""
return subprocess.check_output("bluetoothctl paired-devices", shell=True).decode()
For test purposes, I want to connect a USB device and want to check what is the speed (HS/FS/LS).
I am able to access to Device Descriptor, Endpoint descriptor, interface descriptor but I would like to know the device address which has been allocated by the OS (windows 7)
My code so far :
import usb
busses = usb.busses()
for bus in busses:
for dev in bus.devices:
if dev.idVendor == vendor_id and dev.idProduct == product_id:
print ("Test vehicle %s device FOUND!" %protocol)
print ("iManufacturer : %s" %usb.util.get_string(dev.dev, 256, 1))
print ("iProduct : %s" %usb.util.get_string(dev.dev, 256, 2))
print ("iSerialNumber : %s" %usb.util.get_string(dev.dev, 256, 3))
return dev
print ("Test vehicle %s device NOT FOUND!" %protocol)
Returns :
C:\Python27\Lib\site-packages>python example.py
Test vehicle HS device FOUND!
iManufacturer : Kingston
iProduct : DataTraveler 2.0
iSerialNumber : 5B720A82364A
In the very useful USBview software, there is a section :
ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed: High
Device Address: 0x09
Open Pipes: 2
How do I get these informations ? is it a query to the USB device using pyUSB ? or is it a query to sys ?
Thanks for any help.
There are several more fields available in the device objects (in your code these are named dev).
A quick and dirty way to look at them
def print_internals(dev):
for attrib in dir(dev):
if not attrib.startswith('_') and not attrib == 'configurations':
x=getattr(dev, attrib)
print " ", attrib, x
for config in dev.configurations:
for attrib in dir(config):
if not attrib.startswith('_'):
x=getattr(config, attrib)
print " ", attrib, x
And call it within your "for dev in bus.devices" loop. It looks like the filename might correspond to 'device address', though bus speed is a bit deeper in (dev.configurations[i].interfaces[j][k].interfaceProtocol), and this only has an integer. usb.util might be able to provide you more information based on those integers, but I don't have that module available to me.
Documentation for pyUSB doesn't seem to be very extensive, but this SO question points at the libusb docs which it wraps up.
You can get usb device speed information by pyUSB with this patch https://github.com/DeliangFan/pyusb/commit/a882829859cd6ef3c91ca11870937dfff93fea9d.
Because libusb1.0 has already support to get usb speed information.
These attributes are (nowadays) easily accessible. At least it works for me. https://github.com/pyusb/pyusb/blob/master/usb/core.py
import usb.core
devices = usb.core.find(find_all=True)
dev = next(devices)
print("device bus:", dev.bus)
print("device address:", dev.address)
print("device port:", dev.port_number)
print("device speed:", dev.speed)
first i'm sorry if my english is not very good because i'm french.
I'm a beginner on bluetooth development with pyBluez (i already know TCP and UDP sockets) and i have a little problem with the server.
when i run the following code, my computer seems to be in a listening state but when my phone(nokia xpress music 5800) try to detect it, it doesn't see anything!
and there is two surprising things for me:
1)there is no fonction in my code configuring a name like "my computer". maybe my phone find my address but,because it can't resolve the name by lookup_name()-like function, it considers my computers isn't on?
2)when i replace serversock.bind(("",PORT_ANY)) by serversock.bind(("00:12:34:56:78:9A",PORT_ANY)) where 00:12:34:56:78:9A is the address given by hciconfig tool for my bluetooth device, i'm getting :
_bluetooth.error: (98, 'Address already in use'
just a stupid question because i think the answer is yes bacause of channels:
is it possible to have multiple program listening on the SAME bluetooth interfaces.
i run the program on root
from bluetooth import *
serversock=BluetoothSocket(RFCOMM)
serversock.bind(("",PORT_ANY))
serversock.listen(1)
advertise_service(serversock,"SampleServer",service_classes = [ SERIAL_PORT_CLASS ],profiles = [ SERIAL_PORT_PROFILE ] )
clientsock,clientinfo = serversock.accept()
print "Accepted connection from " , clientinfo
clientsock.send("PyBluez server says Hello!! ")
data = clientsock.recv(1024)
print "received: " , data
clientsock.close()
serversock.close()
thank you
Check the server's visibility with hciconfig:
# hciconfig
hci0: Type: USB
BD Address: 00:11:22:12:34:56 ACL MTU: 192:8 SCO MTU: 64:8
UP RUNNING PSCAN ISCAN
RX bytes:296 acl:0 sco:0 events:26 errors:0
TX bytes:536 acl:0 sco:0 commands:22 errors:0
In case your local device is invisible, set visibility on with:
hciconfig hci0 piscan
Turn off visibility if needed with:
hciconfig hci0 noscan
I have a Bluetooth client on Android that must connect to my computer by RFCOMM and using the UUID 00001101-0000-1000-8000-00805F9B34FB
The PyBluez library is used, as well as Python 2.6. I used the following code from the PyBluez Documentation
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"
It works perfectly fine under Windows 7.
But I have no reaction with another computer on Windows XP, i.e. my code stays at the line "Waiting for connection on RFCOMM channel". My Bluetooth client warns me it is connected, though.
This Windows XP computer Bluetooth configuration allows me to set-up a COM port for serial communications with Bluetooth. If I listen on this configured COM port, I can see my data from the Bluetooth client.
I prefer to have a code working on any Windows computer, and I do not want to configure virtual COM port on these computers. So I would like the above program also working with the Windows XP computer.
What do I miss? It is as if the Windows XP computer do not forward Bluetooth data to my program, even if I disable its capability of reproducing data on a virtual serial port.
It seems the UUID I use is a well known one, but I must use this one to have my program compatible with another specific platform.
The Bluetooth stack on the Windows 7 computer is from Atheros Communications, the one on the Windows XP computer is from Widcomm.
The Widcomm Bluetooth stack installed on your XP has its own API and driver; this API is totally incompatible with the MS Bluetooth stack! (furthermore, you need XP SP2 to use MS Stack, with a compatible dongle too... I've never found one)
So, on Win7, you can use 'sockets' with the MS Stack (even a Broadcom/Widcomm will work, using the MS stack and not the specific API!)
On XP, you need to use another code, compatible with the Widcomm stack...
You can eventually use COMports on XP, connected to the virtual COMs...but you'll get no notification from the stack...