2

I am using Raspbian Stretch 9.4 on a Zero W. The goal is to deploy it headless for long periods of time where it will broadcast a specified bluetooth signal. When someone tries to connect to it, it will automatically pair, log the connected/paired mac address to a file along with an info request out of bluetoothctl. Then it's going to sit and wait for the next request and do the same thing in a loop.

I know this likely involves using dbus and likely an agent in bluez but truth be told I'm drowning trying to understand these scripts and cannot find one that works off stretch to do what I want.

I've tried making an expect script to automate the setup features but couldn't control when a device pairs how to isolate the mac (to send the info command on whatever device connected). I could also use a << EOF setup but again I couldn't figure out how to isolate the MAC of a connected device.

My googling lead me to monitoring the dbus but I have no idea how to get things setup using it. It's way over my head.

So far this is the script I'm working with but it did not log a pairing of an android phone while the script was running:

#!/usr/bin/python

import os
import sys
import signal
import logging
import logging.handlers
import dbus
import dbus.service
import dbus.mainloop.glib
import gobject

#LOG_LEVEL = logging.INFO
LOG_LEVEL = logging.DEBUG
LOG_FILE = "/home/pi/pylog.log"
LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s"
BLUEZ_DEV = "org.bluez.MediaControl1"

def device_property_changed_cb(property_name, value, path, interface, device_path):
    global bus
    if property_name != BLUEZ_DEV:
        return

    device = dbus.Interface(bus.get_object("org.bluez", device_path), "org.freedesktop.DBus.Properties")
    properties = device.GetAll(BLUEZ_DEV)

    logger.info("Getting dbus interface for device: %s interface: %s property_name: %s" % (device_path, interface, property_name))

    if properties["Connected"]:
        bt_addr = "_".join(device_path.split('/')[-1].split('_')[1:])
        logger.INFO("MAC Found: %s" % bt_addr)
        #cmd = "" % bt_addr
        #logger.info("Running cmd: %s" % cmd)
        #os.system(cmd)
    else:
        bt_addr = "_".join(device_path.split('/')[-1].split('_')[1:])
        logger.info("Device: %s has disconnected" % bt_addr)
#        cmd = "for i in $(pactl list short modules | grep module-loopback | grep source=bluez_source.%s | cut -f 1); do pactl unload-module $i; done" % bt_addr
#        logger.info("Running cmd: %s" % cmd)
#        os.system(cmd)

def shutdown(signum, frame):
    mainloop.quit()

if __name__ == "__main__":
    # shut down on a TERM signal
    signal.signal(signal.SIGTERM, shutdown)

    # start logging
    logger = logging.getLogger("bt_auto_loader")
    logger.setLevel(LOG_LEVEL)
    #logger.addHandler(logging.handlers.SysLogHandler(address = "/home/pi/pylog.log"))
    logger.info("Starting to monitor Bluetooth connections")

    # Get the system bus
    try:
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        bus = dbus.SystemBus()
    except Exception as ex:
        logger.error("Unable to get the system dbus: '{0}'. Exiting. Is dbus running?".format(ex.message))
        sys.exit(1)

    # listen for signals on the Bluez bus
    bus.add_signal_receiver(device_property_changed_cb, bus_name="org.bluez", signal_name="PropertiesChanged", path_keyword="device_path", interface_keyword="interface")

    try:
        mainloop = gobject.MainLoop()
        mainloop.run()
    except KeyboardInterrupt:
        pass
    except:
        logger.error("Unable to run the gobject main loop")
        sys.exit(1)

    logger.info("Shutting down")
    sys.exit(0)

Log returned:

INFO:bt_auto_loader:Starting to monitor Bluetooth connections
INFO:bt_auto_loader:Shutting down

This is what dbus monitor is showing when I click pair on an android phone:

signal time=1554344215.452003 sender=:1.3 -> destination=(null destination) serial=351 path=/org/bluez/hci0; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.bluez.Adapter1"
   array [
      dict entry(
         string "Discoverable"
         variant             boolean true
      )
   ]
   array [
   ]
signal time=1554344240.507939 sender=:1.3 -> destination=(null destination) serial=352 path=/org/bluez/hci0/dev_F8_F1_B6_E2_BB_06; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.bluez.Device1"
   array [
      dict entry(
         string "Connected"
         variant             boolean true
      )
   ]
   array [
   ]
signal time=1554344240.527694 sender=:1.0 -> destination=(null destination) serial=3088 path=/org/freedesktop/systemd1; interface=org.freedesktop.systemd1.Manager; member=UnitNew
   string "sys-devices-platform-soc-20201000.serial-tty-ttyAMA0-hci0-hci0:11.device"
   object path "/org/freedesktop/systemd1/unit/sys_2ddevices_2dplatform_2dsoc_2d20201000_2eserial_2dtty_2dttyAMA0_2dhci0_2dhci0_3a11_2edevice"
signal time=1554344240.531963 sender=:1.0 -> destination=(null destination) serial=3089 path=/org/freedesktop/systemd1; interface=org.freedesktop.systemd1.Manager; member=UnitNew
   string "sys-subsystem-bluetooth-devices-hci0:11.device"
   object path "/org/freedesktop/systemd1/unit/sys_2dsubsystem_2dbluetooth_2ddevices_2dhci0_3a11_2edevice"
signal time=1554344246.427736 sender=:1.3 -> destination=(null destination) serial=353 path=/org/bluez/hci0/dev_F8_F1_B6_E2_BB_06; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.bluez.Device1"
   array [
      dict entry(
         string "Connected"
         variant             boolean false
      )
   ]
   array [
   ]
signal time=1554344246.466625 sender=:1.0 -> destination=(null destination) serial=3090 path=/org/freedesktop/systemd1/unit/sys_2dsubsystem_2dbluetooth_2ddevices_2dhci0_3a11_2edevice; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.freedesktop.systemd1.Device"
   array [
      dict entry(
         string "SysFSPath"
         variant             string "/sys/devices/platform/soc/20201000.serial/tty/ttyAMA0/hci0/hci0:11"
      )
   ]
   array [
   ]
signal time=1554344246.478715 sender=:1.0 -> destination=(null destination) serial=3091 path=/org/freedesktop/systemd1/unit/sys_2dsubsystem_2dbluetooth_2ddevices_2dhci0_3a11_2edevice; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.freedesktop.systemd1.Unit"
   array [
      dict entry(
         string "ActiveState"
         variant             string "inactive"
      )
      dict entry(
         string "SubState"
         variant             string "dead"
      )
      dict entry(
         string "StateChangeTimestamp"
         variant             uint64 1554344246457571
      )
      dict entry(
         string "StateChangeTimestampMonotonic"
         variant             uint64 1488121717330
      )
      dict entry(
         string "InactiveExitTimestamp"
         variant             uint64 1554344240525803
      )
      dict entry(
         string "InactiveExitTimestampMonotonic"
         variant             uint64 1488115785558
      )
      dict entry(
         string "ActiveEnterTimestamp"
         variant             uint64 1554344240525803
      )
      dict entry(
         string "ActiveEnterTimestampMonotonic"
         variant             uint64 1488115785558
      )
      dict entry(
         string "ActiveExitTimestamp"
         variant             uint64 1554344246457571
      )
      dict entry(
         string "ActiveExitTimestampMonotonic"
         variant             uint64 1488121717330
      )
      dict entry(
         string "InactiveEnterTimestamp"
         variant             uint64 1554344246457571
      )
      dict entry(
         string "InactiveEnterTimestampMonotonic"
         variant             uint64 1488121717330
      )
      dict entry(
         string "Job"
         variant             struct {
               uint32 0
               object path "/"
            }
      )
      dict entry(
         string "ConditionResult"
         variant             boolean false
      )
      dict entry(
         string "AssertResult"
         variant             boolean false
      )
      dict entry(
         string "ConditionTimestamp"
         variant             uint64 0
      )
      dict entry(
         string "ConditionTimestampMonotonic"
         variant             uint64 0
      )
      dict entry(
         string "AssertTimestamp"
         variant             uint64 0
      )
      dict entry(
         string "AssertTimestampMonotonic"
         variant             uint64 0
      )
   ]
   array [
   ]
signal time=1554344246.490121 sender=:1.0 -> destination=(null destination) serial=3092 path=/org/freedesktop/systemd1; interface=org.freedesktop.systemd1.Manager; member=UnitRemoved
   string "sys-subsystem-bluetooth-devices-hci0:11.device"
   object path "/org/freedesktop/systemd1/unit/sys_2dsubsystem_2dbluetooth_2ddevices_2dhci0_3a11_2edevice"
signal time=1554344246.492135 sender=:1.0 -> destination=(null destination) serial=3093 path=/org/freedesktop/systemd1/unit/sys_2ddevices_2dplatform_2dsoc_2d20201000_2eserial_2dtty_2dttyAMA0_2dhci0_2dhci0_3a11_2edevice; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.freedesktop.systemd1.Device"
   array [
      dict entry(
         string "SysFSPath"
         variant             string "/sys/devices/platform/soc/20201000.serial/tty/ttyAMA0/hci0/hci0:11"
      )
   ]
   array [
   ]
signal time=1554344246.493270 sender=:1.0 -> destination=(null destination) serial=3094 path=/org/freedesktop/systemd1/unit/sys_2ddevices_2dplatform_2dsoc_2d20201000_2eserial_2dtty_2dttyAMA0_2dhci0_2dhci0_3a11_2edevice; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.freedesktop.systemd1.Unit"
   array [
      dict entry(
         string "ActiveState"
         variant             string "inactive"
      )
      dict entry(
         string "SubState"
         variant             string "dead"
      )
      dict entry(
         string "StateChangeTimestamp"
         variant             uint64 1554344246457643
      )
      dict entry(
         string "StateChangeTimestampMonotonic"
         variant             uint64 1488121717400
      )
      dict entry(
         string "InactiveExitTimestamp"
         variant             uint64 1554344240525883
      )
      dict entry(
         string "InactiveExitTimestampMonotonic"
         variant             uint64 1488115785639
      )
      dict entry(
         string "ActiveEnterTimestamp"
         variant             uint64 1554344240525883
      )
      dict entry(
         string "ActiveEnterTimestampMonotonic"
         variant             uint64 1488115785639
      )
      dict entry(
         string "ActiveExitTimestamp"
         variant             uint64 1554344246457643
      )
      dict entry(
         string "ActiveExitTimestampMonotonic"
         variant             uint64 1488121717400
      )
      dict entry(
         string "InactiveEnterTimestamp"
         variant             uint64 1554344246457643
      )
      dict entry(
         string "InactiveEnterTimestampMonotonic"
         variant             uint64 1488121717400
      )
      dict entry(
         string "Job"
         variant             struct {
               uint32 0
               object path "/"
            }
      )
      dict entry(
         string "ConditionResult"
         variant             boolean false
      )
      dict entry(
         string "AssertResult"
         variant             boolean false
      )
      dict entry(
         string "ConditionTimestamp"
         variant             uint64 0
      )
      dict entry(
         string "ConditionTimestampMonotonic"
         variant             uint64 0
      )
      dict entry(
         string "AssertTimestamp"
         variant             uint64 0
      )
      dict entry(
         string "AssertTimestampMonotonic"
         variant             uint64 0
      )
   ]
   array [
   ]
signal time=1554344246.507212 sender=:1.0 -> destination=(null destination) serial=3095 path=/org/freedesktop/systemd1; interface=org.freedesktop.systemd1.Manager; member=UnitRemoved
   string "sys-devices-platform-soc-20201000.serial-tty-ttyAMA0-hci0-hci0:11.device"
   object path "/org/freedesktop/systemd1/unit/sys_2ddevices_2dplatform_2dsoc_2d20201000_2eserial_2dtty_2dttyAMA0_2dhci0_2dhci0_3a11_2edevice"
1
  • 1
    What exactly did you try so far? Could you add your script to the question?
    – jake
    Apr 14, 2019 at 19:06

1 Answer 1

0

I am not sure I have totally understood what your project is doing. One of the things you want to do is record when a device connects or disconnects.

The example below has a class called DeviceMonitor that stores information on all the devices BlueZ knows about. It will do a print statement saying if a device connects or disconnects. You can change those print statements for something more useful.

This uses the pydbus library to access the BlueZ DBus API.

import pydbus
from gi.repository import GLib

bus = pydbus.SystemBus()
mng = bus.get('org.bluez', '/')

class DeviceMonitor:
    def __init__(self, path_obj):
        self.device = bus.get('org.bluez', path_obj)
        self.device.onPropertiesChanged = self.prop_changed
        print(f'Device added to monitor {self.device.Address}')

    def prop_changed(self, iface, props_changed, props_removed):
        """Event handler for a device property change"""
        con_status = props_changed.get('Connected', None)
        if con_status is not None:
            if con_status:
                print(f'Connected {self.device.Address}')
            else:
                print(f'Disconnected {self.device.Address}')

def new_iface(path, iface_props):
    """Check to see if a new device has been added"""
    print('Interface Added')
    device_addr = iface_props.get('org.bluez.Device1', {}).get('Address')
    if device_addr:
        DeviceMonitor(path)

mng.onInterfacesAdded = new_iface

# Get all the known devices and add them to DeviceMonitor
mng_objs = mng.GetManagedObjects()
for path in mng_objs:
    dev_props = mng_objs[path].get('org.bluez.Device1', {})
    if dev_props:
        DeviceMonitor(path)

# Start the eventloop to monitor BlueZ events
mainloop = GLib.MainLoop()
try:
    mainloop.run()
except KeyboardInterrupt:
    mainloop.quit()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.