I’m trying to register a BLE GATT characteristic on a Victron controller running VenusOS using the velib_python library.
My goal: In the end, I would like to have a BLE Characteristic (to put it simply) that I can write to from the outside. When a new value is written via BLE, I want to execute a Python or .sh script with the received value as an argument.
I’ve written a Python script that creates a BLE GATT service and a characteristic using the D-Bus org.bluez.GattManager1
interface, but I’m encountering an issue when attempting to register the application.
Here’s the error message I receive:
Failed to register application: org.bluez.Error.Failed: No object received
From the D-Bus monitor, I can see that a call is made to RegisterApplication
on the GattManager1
interface, but the registration still fails:
method call time=XXX sender=:1.637 -> destination=:1.0 serial=4 path=/org/bluez/hci0; interface=org.bluez.GattManager1; member=RegisterApplication
object path "/org/bluez/example/service0"
The error seems related to BlueZ not receiving the necessary objects (e.g., characteristics) under the service. Here’s a summary of what I’ve tried so far:
- I’ve defined a GATT service class and a characteristic class within my Python script.
- The service contains a method to handle writes to the characteristic (for receiving SSID and password data).
- I’m using the system D-Bus for communication and
bluez
is available on D-Bus.
Has anyone successfully registered a BLE GATT service and characteristic using VenusOS and velib_python? Any insights or examples of working setups would be greatly appreciated!
Thanks in advance!
Python Code
from dbus.service import method, Object
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
import dbus
import os
import sys
class MyCharacteristic(Object):
PATH_BASE = '/org/bluez/example/service/char'
def __init__(self, bus, index, service):
self.path = self.PATH_BASE + str(index)
Object.__init__(self, bus, self.path)
self.service = service
self.value = []
@method(dbus_interface="org.bluez.GattCharacteristic1",
in_signature="ay", out_signature="")
def WriteValue(self, value):
self.value = value
print(f"Received WriteValue: {value}")
# Handle logic for parameter
data = ''.join([chr(byte) for byte in value])
if "parameter:" in data:
self.service.parameter = data.replace("parameter:", "").strip()
if self.service.parameter:
self.service.execute_script()
class MyService(Object):
PATH_BASE = '/org/bluez/example/service'
def __init__(self, bus, index):
self.path = self.PATH_BASE + str(index)
Object.__init__(self, bus, self.path)
self.parameter = None
self.characteristics = []
# Add the MyCharacteristic
self.add_characteristic(MyCharacteristic(bus, 0, self))
def add_characteristic(self, characteristic):
self.characteristics.append(characteristic)
def execute_script(self):
print(f"Executing script.")
# Example shell command
script_command = f"/path/to/my.sh {self.parameter}"
os.system(script_command)
def register_app_cb():
print("GATT application registered")
def register_app_error_cb(error):
print("Failed to register application:", str(error))
mainloop.quit()
def main():
DBusGMainLoop(set_as_default=True)
# Use the system bus for BlueZ interaction
bus = dbus.SystemBus()
# Get the GattManager1 interface on the Bluetooth adapter
service_manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez/hci0'), 'org.bluez.GattManager1')
# Create and register the custom GATT Service
service = MyService(bus, 0)
# Register the service with BlueZ
service_manager.RegisterApplication(service.path, {},
reply_handler=register_app_cb,
error_handler=register_app_error_cb)
global mainloop
mainloop = GLib.MainLoop()
mainloop.run()
if __name__ == "__main__":
main()