Skip to content

Instantly share code, notes, and snippets.

@CynaCons
Last active November 23, 2017 01:07
Show Gist options
  • Save CynaCons/19932ae433b1b32da1a72ebe9a1b2a97 to your computer and use it in GitHub Desktop.
Save CynaCons/19932ae433b1b32da1a72ebe9a1b2a97 to your computer and use it in GitHub Desktop.
Advanced Python BLE example with python-glib and Bluez5
import dbus
import time
"""
This gist will do the following things :
1. Setup GLib and a MainLoop. MainLoop is required to receive signals from the dbus
2. Define a simple callback function that will be associated to the signal "Properties Changed" for a specific object (Characteristic).
The callback function will be called when the characteristic value is updated or it's property changed.
3. Build a Proxy object for the Adapter (see adapter-api) and perform a 10 seconds scan (methods StartDiscovery/StopDiscovery).
After the scan, the adapter is introspected and analyzed to find out which devices were discovered.
The first address discovered is used to build a path for the Device Proxy(see 4).
4. Build a Device Proxy based on the device path built at step 3. Introspect the Device to find the nested Services names.
The name of the second service found during the introspection is used to build a path for the Service Proxy.
I use the second service name since the first Service is usually for properties etc.
5. Build a Service Proxy based on the service name found at the end of step 4. The Service proxy is introspected to find the
nested characteristic names. The first characteristic name is used to build a path for the Characteristic Proxy.
6. Build a Characteristic Proxy based on the characteristic name found at the end of step 5.
The method org.bluez.GattCharacteristic1.StartNotify is called to register a "signal receiver".
The callback function will now be called when a signal "Properties Changed is sent to your application by the Characteristic
"""
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
#Open a connection to the SystemBus
bus = dbus.SystemBus()
"""
This function will be called when a signal "properties-changed" will be sent to your application
"""
def notification_callback(*args, **kwargs):
print("Inside notification callback")
#Build a proxy for the Adapter
adapter_proxy = bus.get_object("org.bluez", "/org/bluez/hci0")
#Call the method StartDiscovery from the adapter api
adapter_proxy.StartDiscovery(dbus_interface="org.bluez.Adapter1")
time.sleep(10);
adapter_proxy.StopDiscovery(dbus_interface="org.bluez.Adapter1")
#Introspect the adapter, print and analyze the xml to find the nearby devices
introspection = adapter_proxy.Introspect(dbus_interface="org.freedesktop.DBus.Introspectable")
#Using lxml library, turn the introspection string into a tree and find the xml tags "node"
#These xml tags nodes will contains the mac addresses of the nearby devices
tree = etree.fromstring(introspection)
#Pretty Print the adapter xml
print etree.tostring(tree, pretty_print=True)
#Parse the xml introspection to find nearby devices
addresses = list()
for child in tree:#Parse the xml tree
if child.tag == 'node':
addresses.append(child.attrib['name'])
#Get the first address found during the xml parsing and build an object path for the Device
device_path = "/org/bluez/hci0/"+addresses[0]
#Build a proxy for the Device using the object path built above
device_proxy = bus.get_object("org.bluez", device_path)
#Connect to the Device using org.bluez.Device1.Connect
device_proxy.Connect(dbus_interface="org.bluez.Device1")
#Repeat the process to find the Services nested in the Device
device_introspection = device_proxy.Introspect(dbus_interface="org.freedesktop.DBus.Introspectable")
tree = etree.fromstring(device_introspection)
services = list()
for child in tree:#Parse the xml tree
if child.tag == 'node':
services.append(child.attrib['name'])
#Get the second Service name found in the introspection xml and build an object path for this Service
service_path = device_path + "/" + services[1]
service_proxy = bus.get_object("org.bluez", "service_path")
#Repeat the process one last time to find the Characteristics nested in the Service
service_introspection = service_proxy.Introspect(dbus_interface="org.freedesktop.DBus.Introspectable")
tree = etree.fromstring(service_introspection)
characteristics = list()
for child in tree:
if child.tag == 'node':
characteristics.append(child.attrib['name'])
#Get the first Characteristic and build the object path
characteristic_path = service_path + "/" + characteristics[0]
characteristic_proxy = bus.get_object("org.bluez", "characteristic_path")
#Call the method org.bluez.GattCharacteristic1.StartNotify
characteristic_proxy.StartNotify(dbus_interface="org.bluez.GattCharacteristic1")
#Register a signal handler that will catch the "Properties Changed".
#The "Properties Changed" signal will emitted when the charcteristic value or properties are changed
bus.add_signal_receiver(notification_callback, dbus_interface="org.freedesktop.DBus.Properties", path=characteristic_path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment