Skip to content

Instantly share code, notes, and snippets.

@studiofuga
Last active March 25, 2021 07:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save studiofuga/249035dd86e1c7c7bb75 to your computer and use it in GitHub Desktop.
Save studiofuga/249035dd86e1c7c7bb75 to your computer and use it in GitHub Desktop.
Bluetooth agent that performs pairing with a fixed pin ("0000").
import dbus
SERVICE_NAME = "org.bluez"
ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1"
DEVICE_INTERFACE = SERVICE_NAME + ".Device1"
def get_managed_objects():
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.freedesktop.DBus.ObjectManager")
return manager.GetManagedObjects()
def find_adapter(pattern=None):
return find_adapter_in_objects(get_managed_objects(), pattern)
def find_adapter_in_objects(objects, pattern=None):
bus = dbus.SystemBus()
for path, ifaces in objects.iteritems():
adapter = ifaces.get(ADAPTER_INTERFACE)
if adapter is None:
continue
if not pattern or pattern == adapter["Address"] or \
path.endswith(pattern):
obj = bus.get_object(SERVICE_NAME, path)
return dbus.Interface(obj, ADAPTER_INTERFACE)
raise Exception("Bluetooth adapter not found")
def find_device(device_address, adapter_pattern=None):
return find_device_in_objects(get_managed_objects(), device_address,
adapter_pattern)
def find_device_in_objects(objects, device_address, adapter_pattern=None):
bus = dbus.SystemBus()
path_prefix = ""
if adapter_pattern:
adapter = find_adapter_in_objects(objects, adapter_pattern)
path_prefix = adapter.object_path
for path, ifaces in objects.iteritems():
device = ifaces.get(DEVICE_INTERFACE)
if device is None:
continue
if (device["Address"] == device_address and
path.startswith(path_prefix)):
obj = bus.get_object(SERVICE_NAME, path)
return dbus.Interface(obj, DEVICE_INTERFACE)
raise Exception("Bluetooth device not found")
#!/usr/bin/python
from __future__ import absolute_import, print_function, unicode_literals
from optparse import OptionParser
import sys
import dbus
import dbus.service
import dbus.mainloop.glib
try:
from gi.repository import GObject
except ImportError:
import gobject as GObject
import bluezutils
BUS_NAME = 'org.bluez'
AGENT_INTERFACE = 'org.bluez.Agent1'
AGENT_PATH = "/test/agent"
bus = None
device_obj = None
dev_path = None
def ask(prompt):
try:
return raw_input(prompt)
except:
return input(prompt)
def set_trusted(path):
props = dbus.Interface(bus.get_object("org.bluez", path),
"org.freedesktop.DBus.Properties")
props.Set("org.bluez.Device1", "Trusted", True)
def dev_connect(path):
dev = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device1")
dev.Connect()
class Rejected(dbus.DBusException):
_dbus_error_name = "org.bluez.Error.Rejected"
class Agent(dbus.service.Object):
exit_on_release = True
def set_exit_on_release(self, exit_on_release):
self.exit_on_release = exit_on_release
@dbus.service.method(AGENT_INTERFACE,
in_signature="", out_signature="")
def Release(self):
print("Release")
if self.exit_on_release:
mainloop.quit()
@dbus.service.method(AGENT_INTERFACE,
in_signature="os", out_signature="")
def AuthorizeService(self, device, uuid):
return
@dbus.service.method(AGENT_INTERFACE,
in_signature="o", out_signature="s")
def RequestPinCode(self, device):
set_trusted(device)
return "0000"
@dbus.service.method(AGENT_INTERFACE,
in_signature="o", out_signature="u")
def RequestPasskey(self, device):
set_trusted(device)
return dbus.UInt32("0000")
@dbus.service.method(AGENT_INTERFACE,
in_signature="ouq", out_signature="")
def DisplayPasskey(self, device, passkey, entered):
print("DisplayPasskey (%s, %06u entered %u)" %
(device, passkey, entered))
@dbus.service.method(AGENT_INTERFACE,
in_signature="os", out_signature="")
def DisplayPinCode(self, device, pincode):
print("DisplayPinCode (%s, %s)" % (device, pincode))
@dbus.service.method(AGENT_INTERFACE,
in_signature="ou", out_signature="")
def RequestConfirmation(self, device, passkey):
set_trusted(device)
return
@dbus.service.method(AGENT_INTERFACE,
in_signature="o", out_signature="")
def RequestAuthorization(self, device):
return
@dbus.service.method(AGENT_INTERFACE,
in_signature="", out_signature="")
def Cancel(self):
print("Cancel")
def pair_reply():
print("Device paired")
set_trusted(dev_path)
dev_connect(dev_path)
mainloop.quit()
def pair_error(error):
err_name = error.get_dbus_name()
if err_name == "org.freedesktop.DBus.Error.NoReply" and device_obj:
print("Timed out. Cancelling pairing")
device_obj.CancelPairing()
else:
print("Creating device failed: %s" % (error))
mainloop.quit()
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
capability = "NoInputNoOutput"
parser = OptionParser()
parser.add_option("-i", "--adapter", action="store",
type="string",
dest="adapter_pattern",
default=None)
parser.add_option("-c", "--capability", action="store",
type="string", dest="capability")
parser.add_option("-t", "--timeout", action="store",
type="int", dest="timeout",
default=60000)
(options, args) = parser.parse_args()
if options.capability:
capability = options.capability
path = "/test/agent"
agent = Agent(bus, path)
mainloop = GObject.MainLoop()
obj = bus.get_object(BUS_NAME, "/org/bluez");
manager = dbus.Interface(obj, "org.bluez.AgentManager1")
manager.RegisterAgent(path, capability)
print("Agent registered")
# Fix-up old style invocation (BlueZ 4)
if len(args) > 0 and args[0].startswith("hci"):
options.adapter_pattern = args[0]
del args[:1]
if len(args) > 0:
device = bluezutils.find_device(args[0],
options.adapter_pattern)
dev_path = device.object_path
agent.set_exit_on_release(False)
device.Pair(reply_handler=pair_reply, error_handler=pair_error,
timeout=60000)
device_obj = device
else:
manager.RequestDefaultAgent(path)
mainloop.run()
#adapter.UnregisterAgent(path)
#print("Agent unregistered")
@mcavalcantib
Copy link

Do you have some email that we can talk about this scripts?

@studiofuga
Copy link
Author

Yes, I have. What is the topic? Can we discuss it here?

@mcavalcantib
Copy link

Did this scripts still working? I've tested with Android 9 and a Raspberry with Raspbian and Bluez5, and when I put the pin, I get a "Wrong pin" message. But when I try on Andoid 6, it works fine.
Did you have some problem like this?

@studiofuga
Copy link
Author

Hi, sorry I don't use it since 4 years. The project is closed so I can't even help on testing it.
The script was adapted by the bluez test agent, so your best bet is to double check the difference with the current version. Perhaps something has changed on the interface in the meantime.
Please, let me know if you are able to fix it. Thanks

@dmcallejo
Copy link

@MBezerril I'm having the same problem. On Android 9 it doesn't work at all, but 8.1, 7.1.2 and prior versions work fine.
Have you found a solution?

@mcavalcantib
Copy link

@dmcallejo I found a thread in Raspberry Forum, and with others that have the same problem and after some tests, found that the problem is in Bluez drivers.
Here is the thread: https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=195090&sid=a1318874b8ef63d12e480736d4e63641&start=25
Only the Bluez Developers can make a fix

@dmcallejo
Copy link

@MBezerril Thank you! I paired the phone via bluetoothctl for now, but definitely this should be fixed. Thank you for the thread, I'll look it out and watch it for updates.

@embeddedshiv
Copy link

Hello, Will you please help me to know, How can I configure the BLE Gatt service to accept the password from the Android/IOS App?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment