lunedì 4 marzo 2013

Sensore di prossimita' Bluetooth



Uno degli utilizzi del bluetooth e' quello di utilizzare una apparecchiatura come una chiave per permettere l'accesso ad un servizio, nel momento in cui l'apparecchio ed il suo proprietario si allontana si puo'  effettuare la disconnessione o lo spengimento

Questa modalita' e' definita come "sensore di prossimita'" e vi sono due modalita'

1) Modalita' con accoppiamento
In generale e' possibile ottenere la qualita' del segnale (RSSI) di un apparecchio BT (e quindi la sola lontananza/vicinanza) solamente quando e' stato effettuato l'accoppiamento (o connessione)

In modo manuale si puo' seguire la presente procedura il seguente script in cui deve essere inserito il MAC address Bluetooth del dispositivo da monitorare

--------------------------------------------------------

#!/bin/bash
#set -o verbose sh -v
# Copied from Steven on http://gentoo-wiki.com/Talk:TIP_Bluetooth_Proximity_Monitor

# These are the sections you'll need to edit

 # You'll need to use the MAC address of your phone here
DEVICE="1C:66:AA:76:72:18" 

# How often to check the distance between phone and computer in seconds
CHECK_INTERVAL=2

# The RSSI threshold at which a phone is considered far or near
THRESHOLD=-13

# The command to run when your phone gets too far away
FAR_CMD='echo lontano'

# The command to run when your phone is close again
NEAR_CMD='echo lontano'

HCITOOL="/usr/bin/hcitool"
STARTX_PID=0
DEBUG="/tmp/btproximity.log"

connected=0

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

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

check_connection

while [[ $connected -eq 0 ]]; do
    check_connection
    sleep 3
done

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

state="near"
while /bin/true; do

    check_connection

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

        if [[ $rssi -le $THRESHOLD ]]; then
            if [[ "$state" == "near" ]]; then
                msg "*** Device \"$name\" [$DEVICE] has left proximity"
                state="far"
                $FAR_CMD > /dev/null 2>&1
            fi
        else
            if [[ "$state" == "far" && $rssi -ge $[$THRESHOLD+2] ]]; then
                msg "*** Device \"$name\" [$DEVICE] is within proximity"
                state="near"
                $NEAR_CMD > /dev/null 2>&1
                STARTX_PID=$(pgrep startx)
            fi
        fi
        msg "state = $state, RSSI = $rssi"
    fi

    sleep $CHECK_INTERVAL
done

--------------------------------------------------------

l'output e' di questo tipo
--------------------------------------------------------

Read RSSI failed: Input/output error
state = near, RSSI =
Attempting connection...
Connected.
state = near, RSSI = 0
state = near, RSSI = 0
Attempting connection...
Connected.
state = near, RSSI = 0
state = near, RSSI = -8
Attempting connection...
Connected.
state = near, RSSI = -11
*** Device "" [1C:66:AA:76:72:18] has left proximity
state = far, RSSI = -21
Attempting connection...
Connected.
state = far, RSSI = -23
state = far, RSSI = -24
Attempting connection...
state = far, RSSI = -20
state = far, RSSI = -22

-------------------------------------------------------

2) Modalita' senza accoppiamento
Negli esempi di PyBluez e' presente un esempio in examples/advanced denominato inquiry-with-rssi.py in cui e' possibile ottenere il valore di RSSI senza effettuare l'accoppiamento (ovviamente il dispositivo BT deve essere visibile)

L'output e' di questo tipo
--------------------------------------------------------

current inquiry mode is 1
[1C:66:AA:76:72:18] RSSI: [-46]
[00:1B:EE:58:93:22] RSSI: [-44]
current inquiry mode is 1
[00:1B:EE:58:93:22] RSSI: [-47]
[1C:66:AA:76:72:18] RSSI: [-46]
[30:17:C8:C7:9A:A4] RSSI: [-82]
current inquiry mode is 1
[00:1B:EE:58:93:22] RSSI: [-76]
[1C:66:AA:76:72:18] RSSI: [-79]
current inquiry mode is 1
[1C:66:AA:76:72:18] RSSI: [-72]
[30:17:C8:C7:9A:A4] RSSI: [-81]
[00:1B:EE:58:93:22] RSSI: [-79]
current inquiry mode is 1
[30:17:C8:C7:9A:A4] RSSI: [-83]
[1C:66:AA:76:72:18] RSSI: [-73]
[00:1B:EE:58:93:22] RSSI: [-79]
current inquiry mode is 1
[30:17:C8:C7:9A:A4] RSSI: [-81]
[00:1B:EE:58:93:22] RSSI: [-78]
current inquiry mode is 1
[30:17:C8:C7:9A:A4] RSSI: [-79]
[1C:66:AA:76:72:18] RSSI: [-73]
-------------------------------------------------


Il problema generale e' che il valore di RSSI non e' solo funzione della distanza ma anche della presenza di interferenze come i muri e della potenza delle antenne di ogni singolo dispositivo. Inoltre il valore, tenendo fermo il dispositivo, e'ì piuttosto oscillante per cui deve essere preso un valore medio. Per terminare la scansione dei dispositivi BT e' piuttosto lenta