Last active
November 23, 2017 01:07
-
-
Save CynaCons/19932ae433b1b32da1a72ebe9a1b2a97 to your computer and use it in GitHub Desktop.
Advanced Python BLE example with python-glib and Bluez5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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