RdJong
Posts: 11
Joined: Thu Aug 21, 2014 7:51 pm
Location: Amsterdam, The Netherlands

Run script when Bluetooth connects

Thu Aug 21, 2014 7:55 pm

Hi,

I want to run when a phone connects with Bluetooth to my RPi.
How to make this possible?

Thanks!

User avatar
Douglas6
Posts: 4769
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Run script when Bluetooth connects

Thu Aug 21, 2014 8:34 pm

Probably the best way is to monitor the dbus system bus for 'connect' messages from Bluez. I've got some python code I'll post later if that would help. There's also a simple-monitor python sample script somewhere in the Bluez directory.

RdJong
Posts: 11
Joined: Thu Aug 21, 2014 7:51 pm
Location: Amsterdam, The Netherlands

Re: Run script when Bluetooth connects

Thu Aug 21, 2014 8:35 pm

Douglas6 wrote:Probably the best way is to monitor the dbus system bus for 'connect' messages from Bluez. I've got some python code I'll post later if that would help. There's also a simple-monitor python sample script somewhere in the Bluez directory.
If you'll post the code; yes please! :)

The idea is to display "Device connected" to the PiFace when their is a connection.

User avatar
Douglas6
Posts: 4769
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Run script when Bluetooth connects

Thu Aug 21, 2014 10:46 pm

Ok, you may have to install some Python modules

Code: Select all

sudo apt-get install python-gobject python-dbus
Here's the code that I have tested in a file called 'btminder'

Code: Select all

#!/usr/bin/env python

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

LOG_LEVEL = logging.INFO
#LOG_LEVEL = logging.DEBUG
LOG_FILE = "/dev/stdout"
#LOG_FILE = "/var/log/syslog"
LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s"

def device_property_changed_cb(property_name, value, path, interface):
    device = dbus.Interface(bus.get_object("org.bluez", path), "org.bluez.Device")
    properties = device.GetProperties()

    if (property_name == "Connected"):
        action = "connected" if value else "disconnected"
#
# Replace with your code to write to the PiFace
#
        print("The device %s [%s] is %s " % (properties["Alias"], properties["Address"], action))

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

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

    # start logging
    logging.basicConfig(filename=LOG_FILE, format=LOG_FORMAT, level=LOG_LEVEL)
    logging.info("Starting btminder to monitor Bluetooth connections")

    # Get the system bus
    try:
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        bus = dbus.SystemBus()
    except Exception as ex:
        logging.error("Unable to get the system dbus: '{0}'. Exiting btminder. 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="PropertyChanged",
            dbus_interface="org.bluez.Device", path_keyword="path", interface_keyword="interface")

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

    logging.info("Shutting down btminder")
    sys.exit(0)
You'll need to run it as root, to get access to the system bus:

Code: Select all

sudo python btminder
Hope it helps. Let me know if you have questions.

RdJong
Posts: 11
Joined: Thu Aug 21, 2014 7:51 pm
Location: Amsterdam, The Netherlands

Re: Run script when Bluetooth connects

Sun Aug 24, 2014 3:33 pm

Douglas6 wrote:Hope it helps. Let me know if you have questions.
Hi, the terminal says: "The device iPhone van Rick [xx:xx:xx:xx:xx] is connected". But after a few seconds, my iPhone says: "Pairing Unsuccesful: Make sure "Pi" is turned on, in range, and is ready to pair".

How to accept automatically connection?

User avatar
Douglas6
Posts: 4769
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Run script when Bluetooth connects

Sun Aug 24, 2014 6:04 pm

Bluetooth devices will 'accept connections automatically' if and only if they have previously been paired and trusted.
Pairing and trusting takes several steps:
1: Discovery) The Pi (in this case) must be in discoverable mode, so the phone can, well, discover it.
2: Authentication) The Pi must be running a Bluetooth agent program, that will receive (typically) a PIN code from the phone, and accept it as a valid code.
3: Authorization) The Pi then should 'trust' the device, so that future connections from this device no longer need to be authorized.

Pairing and trusting are typically done once for a device like a phone, and so can be done 'manually'. After that, as I said, connections are automatic. You can use Bluetooth Manager to put your Pi into discovery mode and pair and trust it. You can also use some Bluez command-line helper programs, such as bluez-test-discovery for discovery, bluez-simple-agent for authentication, and bluez-test-device for authorization. These are all python scripts in /usr/bin/, so you can easily study the source code.

RdJong
Posts: 11
Joined: Thu Aug 21, 2014 7:51 pm
Location: Amsterdam, The Netherlands

Re: Run script when Bluetooth connects

Sun Aug 24, 2014 6:06 pm

Douglas6 wrote:Bluetooth devices will 'accept connections automatically' if and only if they have previously been paired and trusted.
Pairing and trusting takes several steps:
1: Discovery) The Pi (in this case) must be in discoverable mode, so the phone can, well, discover it.
2: Authentication) The Pi must be running a Bluetooth agent program, that will receive (typically) a PIN code from the phone, and accept it as a valid code.
3: Authorization) The Pi then should 'trust' the device, so that future connections from this device no longer need to be authorized.

Pairing and trusting are typically done once for a device like a phone, and so can be done manually. After that, as I said, connections are automatic. You can use Bluetooth Manager to put your Pi into discovery mode and pair and trust it. You can also use some Bluez command-line helper programs, such as bluez-test-discovery for discovery, bluez-simple-agent for authentication, and bluez-test-device for authorization. These are all python scripts in /usr/bin/, so you can easily study the source code.
So I can't make an device that accept incoming devices.

User avatar
Douglas6
Posts: 4769
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Run script when Bluetooth connects

Sun Aug 24, 2014 6:14 pm

Yes, you can, once you understand the process. Use the python scripts I listed as models for your own agent.

RdJong
Posts: 11
Joined: Thu Aug 21, 2014 7:51 pm
Location: Amsterdam, The Netherlands

Re: Run script when Bluetooth connects

Tue Aug 26, 2014 12:11 pm

Douglas6 wrote:Yes, you can, once you understand the process. Use the python scripts I listed as models for your own agent.
Can you help me please. I don't know where to begin.

User avatar
Douglas6
Posts: 4769
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Run script when Bluetooth connects

Tue Aug 26, 2014 1:23 pm

I have been trying to help you. I've walked you through the pairing process, I've given you code for monitoring Bluez signals on dbus, I've pointed you at other python scripts that do exactly what you want to do. It's time for you to help yourself. Use Google and search this forum ('bluetooth', 'bluez', 'pairing', 'dbus'); there's all the information you need available. Study the scripts I mentioned, everything you need to pair and trust is in there. If you have specific questions, go ahead and ask, but you're going to have to do most of the work yourself.

[EDIT: Perhaps I didn't account for your current programming knowledge; this IS the beginners forum. So, before even thinking about programming for Bluetooth, you have to know how to use nano or idle, basic programming concepts, how to read, write, and run Python scripts, and some basics of Linux and running commands. Again, forum searches and Google are important tools.]

RdJong
Posts: 11
Joined: Thu Aug 21, 2014 7:51 pm
Location: Amsterdam, The Netherlands

Re: Run script when Bluetooth connects

Sat Aug 30, 2014 12:41 pm

Douglas6 wrote:I have been trying to help you. I've walked you through the pairing process, I've given you code for monitoring Bluez signals on dbus, I've pointed you at other python scripts that do exactly what you want to do. It's time for you to help yourself. Use Google and search this forum ('bluetooth', 'bluez', 'pairing', 'dbus'); there's all the information you need available. Study the scripts I mentioned, everything you need to pair and trust is in there. If you have specific questions, go ahead and ask, but you're going to have to do most of the work yourself.

[EDIT: Perhaps I didn't account for your current programming knowledge; this IS the beginners forum. So, before even thinking about programming for Bluetooth, you have to know how to use nano or idle, basic programming concepts, how to read, write, and run Python scripts, and some basics of Linux and running commands. Again, forum searches and Google are important tools.]
Thanks, I'm student of Software Engineering.
What file must I have to make this gonna work?

otec
Posts: 1
Joined: Fri Feb 05, 2016 12:32 am

Re: Run script when Bluetooth connects

Sun Feb 07, 2016 6:24 pm

Hi Guys,

Thank you very much for implementing this script ! It was a very good learning for me.

I wanted to extend it and make it work with recent Bluez5, as a number of things changed in DBus interface.
The main thing that has changed is that Bluez5 now uses a generic properties container: org.freedesktop.DBus.Properties. So there is no more GetProperties() method on individual interfaces.

I'm attaching my version of script that works on Jessie with Pulseaudio 8 and Bluez 5.23.

Note, the script only loads module-loopback and doesn't unload it, as it seems Pulseaudio 8 does it automatically when device disconnects from bluetooth anyway.

Code: Select all

#!/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 = "/dev/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:])
        cmd = "pactl load-module module-loopback source=bluez_source.%s" % 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 = "/dev/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)
I've installed this script as a service in systemd using following steps:

Code: Select all

cd /etc/systemd/system
create this file

Code: Select all

/etc/systemd/system/pulseaudio-auto-load.service
Paste this:

Code: Select all

[Unit]
Description=Pulse Audio

[Service]
User=pulse
Type=simple
ExecStart=/etc/pulse/pulseaudio-auto-loopback.py

[Install]
WantedBy=multi-user.target
Run this:

Code: Select all

sudo systemctl enable pulseaudio-auto-load.service
sudo systemctl start pulseaudio-auto-load.service
Run this to make sure it has started:

Code: Select all

ps uax | grep pulseaudio-auto-loop
You should see this:

Code: Select all

pulse     1874  0.1  1.2  18148 11552 ?        Ss   18:13   0:00 /usr/bin/python /etc/pulse/pulseaudio-auto-loopback.py
Now connect your phone via bluetooth and start playing a song. module-loopback now should be automatically loaded and you should hear the sound.

The script logs stuff into journal, so you can see its output by running this command:

Code: Select all

sudo journalctl -n 50 -f

Hope this helps. Asking me anything if anything.

vitalic
Posts: 34
Joined: Tue Sep 20, 2016 7:29 pm

Re: Run script when Bluetooth connects

Wed Jul 12, 2017 8:22 pm

Hallo,

got to dig this thread out again.

When I start the script, it only shows the startup line saying that btminder started monitoring.

Connection is enabled to Pi via BT. My system is the last Jessie distro. running bluez 5.43 .

What can I do to make this script work ?

User avatar
Douglas6
Posts: 4769
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Run script when Bluetooth connects

Wed Jul 12, 2017 8:42 pm

And what happens when you connect your phone? What are the contents of /dev/log telling you?

[EDIT: Are you running my code (which is outdated and should error out) or otec's code which should work, but you'll need to update for your purposes (he uses it to load a PulseAudio loopback module, which would have been better done with a PulseAudio module)?]

Jawn78
Posts: 2
Joined: Tue Aug 21, 2018 10:38 pm

Re: Run script when Bluetooth connects

Tue Aug 21, 2018 11:06 pm

Douglas6 wrote:
Thu Aug 21, 2014 10:46 pm
Ok, you may have to install some Python modules

Code: Select all

sudo apt-get install python-gobject python-dbus
Here's the code that I have tested in a file called 'btminder'

Code: Select all

#!/usr/bin/env python

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

LOG_LEVEL = logging.INFO
#LOG_LEVEL = logging.DEBUG
LOG_FILE = "/dev/stdout"
#LOG_FILE = "/var/log/syslog"
LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s"

def device_property_changed_cb(property_name, value, path, interface):
    device = dbus.Interface(bus.get_object("org.bluez", path), "org.bluez.Device")
    properties = device.GetProperties()

    if (property_name == "Connected"):
        action = "connected" if value else "disconnected"
#
# Replace with your code to write to the PiFace
#
        print("The device %s [%s] is %s " % (properties["Alias"], properties["Address"], action))

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

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

    # start logging
    logging.basicConfig(filename=LOG_FILE, format=LOG_FORMAT, level=LOG_LEVEL)
    logging.info("Starting btminder to monitor Bluetooth connections")

    # Get the system bus
    try:
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        bus = dbus.SystemBus()
    except Exception as ex:
        logging.error("Unable to get the system dbus: '{0}'. Exiting btminder. 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="PropertyChanged",
            dbus_interface="org.bluez.Device", path_keyword="path", interface_keyword="interface")

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

    logging.info("Shutting down btminder")
    sys.exit(0)
You'll need to run it as root, to get access to the system bus:

Code: Select all

sudo python btminder
Hope it helps. Let me know if you have questions.

Do you have an update to this code. I am trying to put together a script to trip a relay on one of my pins when a bluetooth device pairs.

User avatar
Douglas6
Posts: 4769
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Run script when Bluetooth connects

Wed Aug 22, 2018 1:18 am

Yikes. That code was written 4 years ago (to the day!) I can hardly remember what I had for breakfast.

There will be some changes needed. BlueZ 5 made significant changes to the DBus interface, including the interface names ("org.bluez.Device" is now "org.bluez.Device1", for example.) I can't think of what else might have changed, I'm afraid you'll need to consult the BlueZ 5 DBus documentation.

[EDIT: I just noticed that otec updated my code for BlueZ 5 in this thread. I would use that for starters. Oh, and pairing is not connecting; don't get confused.]

Return to “Beginners”