Gentoo Wiki



Bluetooth Proximity Monitor

This article is part of the Tips & Tricks series.
Terminals / Shells Network X Window System Portage System Filesystems Kernel Other


Here's the idea: I have a bluetooth phone. When I walk away from my computer, I want the screen to lock. When I come back, I want the screen to unlock. Sound simple? Well, it is! First, you need to get bluetooth working and you need to be able to connect to your phone. If you haven't done that yet, see here.

Note: KDEbluetooth 1.0-beta3 comes with a nice GUI to do this. (You will need bluez-3.*)
Note: BlueProximity also comes with a nice GUI to do this. (You will need bluez-3.*), it gives a nice GTK+ GUI and has different settings for locking and unlocking distance.

Here's how it works. The following bash script will tell hcitool to connect to your phone and get the RSSI (Received Signal Strength Indicator). If your RSSI falls below the threshold, it calls the "FAR" command, when you come back, it calls the "NEAR" command. At the beginning of the script, there are several variables you'll want to change:

DEVICEthe bluetooth address of your phone.
CHECK_INTERVAL how often the script checks the RSSI of your phone.
THRESHOLD the RSSI at which you want the script to know you are "away". -10 works best for me, but you may have to test this by setting your phone at the distance you want your screen to lock, and run 'hcitool rssi <addr>' to get the desired number.
FAR_CMD the command to run to when the RSSI goes below the THRESHOLD
NEAR_CMD the command to run when the RSSI comes back above the THRESHOLD.
DEBUG set this to /dev/tty if you're testing, and set it to a file if you want a log.

The script must be run as root so that hcitool can connect to the bluetooth device. The one problem I found was how to successfully unlock the screensaver from a script. Using xscreensaver -deactivate will only simulate what happens when you move the mouse or when a key is pressed. If your screen is locked, it will stay locked. If you want the screen to automatically unlock, you have to kill xscreensaver and restart it. The problem is that you can't restart xscreensaver as root (as far as I can know), so I the only way I could make the script run as a normal user was to setuid the hcitool program. to do this, simply:

chmod +s /usr/bin/hcitool

Please change the $DEBUG variable to something writeable by the user. Note: When using GNOME or KDE, both environments bring their own screensaver daemon which is fully controlable using D-BUS (GNOME) or DCOP (KDE). It can be called to lock AND to unlock the screen without a password.

If you don't need to kill and restart xscreensaver when you come back, you can just run the script as root and leave hcitool as is.

Tasty bit


I used have the RSSI signal drop when I am infront of my pc using a Nokia 6600. the new bluez 2.25 fixs this issue. I suggest upgrading to the current bluez version.

enough talk... here's the script!

File: /usr/local/bin/btproximity

START_CMD='/usr/bin/xscreensaver -nosplash'
FAR_CMD='/usr/bin/xscreensaver-command -lock'
NEAR_CMD='/usr/bin/killall xscreensaver'
#You really shouldn't kill -9 xscreensaver. 
#From help: (Note that one must *never* kill xscreensaver with -9!)


function msg {
    echo "$1" >> $DEBUG

function check_connection {
    for s in `$HCITOOL con`; do
        if [[ "$s" == "$DEVICE" ]]; then
    if [[ $found == 1 ]]; then
       msg 'Attempting connection...'
        if [ -z "`$HCITOOL cc $DEVICE 2>&1`" ]; then
            msg 'Connected.'
            msg "ERROR: Could not connect to device $DEVICE."

function check_xscreensaver {
    PID=`ps -C xscreensaver --no-heading | awk '{ print $1 }'`
    if [ "$PID" == "" ];  then
        $START_CMD &


while [[ $connected -eq 0 ]]; do

name=`$HCITOOL name $DEVICE`
msg "Monitoring proximity of \"$name\" [$DEVICE]";

while /bin/true; do


    if [[ $connected -eq 1 ]]; then
        rssi=`$HCITOOL rssi $DEVICE | sed -e 's/RSSI return value: //g'`

        if (( $rssi <= $THRESHOLD )); then
            if [[ "$state" == "near" ]]; then
                msg "*** Device \"$name\" [$DEVICE] has left proximity"
                $FAR_CMD > /dev/null 2>&1
            if [[ "$state" == "far" ]]; then
                msg "*** Device \"$name\" [$DEVICE] is within proximity"
                $NEAR_CMD > /dev/null 2>&1
                $START_CMD &
        #msg "state = $state, RSSI = $rssi, PID = $PID"



And, for KDE users, inspired by the above script. Tested with my Sony Ericsson K750i and works perfectly. Also tested with Samsung D600, works great.

File: /usr/local/bin/btproximity

# BTProximity by Thomas Kear <>
# Inspired by scripts from, but designed for KDE users
# No warranty expressed or implied, if it breaks you get to keep both pieces.

# TODO: make the script disconnect on exit, rather than leaving open rfcomm channel. 

DEVICE="00:12:EE:07:95:48"  # Use 'hcitool scan' to find
INTERVAL="2"  # Seconds
MIN_RSSI="-9"  # Min = -10
DATE="date +%X"  # Format to log times in, default = HH:MM:SS (24 hour), 'date --help' for info

log () {
	# Log to console
	echo $1

	# Log to file
	#echo $1 >> /var/log/BTProximity.log

# Script to run when device leaves proximity
device_out () {
	log "`${DATE}`: Device left proximity"
	# Only change commands below this line
	dcop kdesktop KScreensaverIface lock &> /dev/null  # Start KDE Screensaver
	amixer -c 0 cset numid=216 0 &> /dev/null &  # Mutes speakers on an audigy 2zs, will need modifying for other cards.

#Script to run when device enters proximity
device_in () {
	log "`${DATE}`: Device entered proximity"
	# only change commands below this line
	killall -9 kdesktop_lock &> /dev/null &  #  Stop KDE Screensaver.  -9 might seem a bit harsh, but works fine
	amixer -c 0 cset numid=216 1 &> /dev/null &  # Unmutes speakers, as above.

#  This keeps trying to connect until it succeeds, may cause a few % CPU usage, but better than failing to unlock
connect () {
	while `check_disconnected`
		/usr/bin/hcitool cc ${DEVICE}
		if `check_connected`
			log "`${DATE}`: Connected to `${HCITOOL} name ${DEVICE}` (${DEVICE})"
			sleep 3  # RSSI returns stupid values if measured immediately after connecting, wait a couple of seconds

#Returns 0 if connected, 1 otherwise
check_connected () {
	[[ -n `${HCITOOL} con | grep ${DEVICE}` ]] && return 0 || return 1
#Opposite of above, 1 if connected
check_disconnected () {
	[[ -z `${HCITOOL} con | grep ${DEVICE}` ]] && return 0 || return 1

while `/bin/true`
	#Connect to bluetooth device
	check_disconnected && connect
	#Get RSSI from bluetooth device
	rssi=`${HCITOOL} rssi ${DEVICE} | gawk -F\:\  '{print $2}'`
	if (( ${rssi} <= ${MIN_RSSI} ))
		# Exit proximity
		[[ ${proximity} == "in" ]] && device_out
		# Enter proximity
		[[ ${proximity} == "out" ]] && device_in
	# Wait for interval set at the top, and cycle
	sleep ${INTERVAL}

login guard

I hate calling to a mate of mine who seems online in ICQ, only to see he is not there. I decided to fix it from my side by using the previous script to log me in and out automatically. I had to modify the previous script and I use this to start that script automaticly.

File: /etc/init.d/btproximity

# this will start the Bluetooth proximity script, that logs me in when my
# bluetooth phone is near the pc, and logs-out when I walk away

USER=<your user>
depend() {
        need bluetooth

start() {
        ebegin "Starting BT Proximity"
        start-stop-daemon --start  --quiet --background --chuid "$USER" --exec /usr/local/bin/
        sleep 1
        eend $? "Failed to start BT proximity"
stop() {
        ebegin "Stopping BT Proximity"
        start-stop-daemon --stop --quiet
        eend ${?} # "Failed to stop BT proximity"

Just put the user name instead of <your user>

Concerns or Compliments? Please use the Discussion section.

Retrieved from ""

Last modified: Mon, 15 Sep 2008 04:56:00 +0000 Hits: 31,585