Bonjour, voilà un petit article pour expliquer comment faire de la détection de présence avec une clé USB Bluetooth connectée à un Raspberry Pi.

Le principe est d’envoyer une requête Bluetooth au téléphone de la personne pour savoir si celle-ci est présente ou non.
Cette méthode est bien plus fiable que l’utilisation de la position GPS du téléphone et bien moins énergivore que les requêtes réseau de type PING en WiFi qui consomment la batterie des SmartPhones.

N’importe quelle clé USB Bluetooth fait l’affaire à condition qu’elle ait des drivers Linux, le plus simple est d’acheter un clé compatible Raspberry Pi.

Ensuite, il faudra installer le packet « bluez » :
sudo apt-get install bluez -y

Puis créer un fichier presence.sh avec le contenu suivant :

#!/bin/bash
 
BLUETOOTHADDRCLEM="70:3E:AC:2A:9A:00"    # Phone MAC address 
BLUETOOTHNAMECLEM="*Clément*"           # Phone name (or juste a part with *)
SLEEPTIME=30   # Check interval in s 
 
COUNTPRESENTCLEM=0
COUNTABSENTCLEM=0
 
while true
do
    DEVICECLEM=`hcitool name $BLUETOOTHADDRCLEM`
 
    if [[ $DEVICECLEM = $BLUETOOTHNAMECLEM ]]
    then
        COUNTPRESENTCLEM=$((COUNTPRESENTCLEM+1))
    else
        COUNTABSENTCLEM=$((COUNTABSENTCLEM+1))
    fi
 
        if [[ "$COUNTPRESENTCLEM" = 1 ]]        # 1 confirmation is OK to be sure Clement is here
        then
                # Do something here
                curl http://10.10.10.10/restapi/Presence_Clement/state/on
                COUNTABSENTCLEM=0
                echo "$(date) - Clement est present"
        fi
 
        if [[ "$COUNTABSENTCLEM" = 3 ]] # We need 3 confirmations to be sure Clement is really away
        then
                # Do something here
                curl http://10.10.10.10/restapi/Presence_Clement/state/off
                COUNTPRESENTCLEM=0
                echo "$(date) - Clement est absent"
        fi
 
    echo "$(date) - confirmation presence: $COUNTPRESENTCLEM"
    echo "$(date) - confirmation absence: $COUNTABSENTCLEM"
    sleep $SLEEPTIME
done

Pour connaitre l’adresse MAC de son téléphone, il faut activer le mode « découverte » dans les réglages (sur iOS, entrez dans le menu : Réglages->Bluetooth) puis lancez la commande suivante sur le Raspberry :

$ hcitool scan
Scanning ...
70:3E:AC:2A:9A:00 iPhone de Clément

Remplacez l’adresse MAC par la votre dans le script, le nom du téléphone et surtout l’action à executer lorsque le téléphone est détecté (généralement une requête cURL vers l’API de votre système domotique).

Enfin, ajoutez les droits d’executions au script « sudo chmod +x presence.sh » et tester par « ./presence.sh ».
Si tout est bon, il ne reste plus qu’à lancer le script en mode « démon ». Pour ça j’utilise Supervisor.

Précisions

Pourquoi avons nous besoin de l’adresse MAC Bluetooth du téléphone plutôt que simplement « scanner » les appareils à portés ?
Pour des questions de confidentialité, les iPhones (et sans doute les autres SmartPhones) ne diffusent plus de « Beacons » lorsque le Bluetooth est activé. Il faut leur envoyer une requête directement sur leur adresse MAC pour obtenir une réponse.

Est-ce que cela fonctionne uniquement avec les Smartphones ?
Dans l’absolu, tout appareil équipé de Bluetooth peut faire l’affaire, comme les bracelets tracker d’activités. Par contre, j’ai testé avec ma Pebble (version 1) sans succès, puisque celle-ci finie par planter après quelques minutes…

Pourquoi attendre 3 confirmations pour déclarer l’absence d’une personne ?
Au début il arrivait que des requêtes tombaient en timeout même si mon téléphone était bien présent, du coup, je me retrouvais dans le noir… Avec 3 confirmations je n’ai plus ce soucis.

Comment faire s’il y a plusieurs personnes dans le logement ?
Il suffit de dupliquer le code autant de fois que de personne en changeant l’adresse MAC cible.

Si le logement est trop grand et la porté du Bluetooth trop faible ?
Certain dongle bluetooth (en version 4.0) peuvent aller jusqu’à 100m, mais si ce n’est pas suffisant, il suffit de mettre plusieurs Raspberry avec le même script. Vous pouvez même rajouter une notion de zone pour savoir où la personne se situe précisément.

Pourquoi faire de la détection de présence ?
J’utilise ce principe pour de nombreux scénarios domotiques, ainsi lorsque je quitte le logement, les lumières s’éteignes et la musique s’arrête. Si je rentre, les lumières s’allument (s’il fait sombre/nuit) et un message audio sur le Sonos me souhaite la bienvenue avec quelques infos utiles comme la température :)

 

[Mise à jour aout 2018]

Je n’utilise plus le Bluetooth car au bout d’un moment cela fait planter la stack bluetooth de mon iPhone 6 et je dois passer en mode avion pour la réinitialiser. A la place j’utilise le WiFi, si l’iPhone est connecté au réseau WiFi alors je suis présent. Jusqu’à iOS 11.4 l’iPhone répondait au ping, ce n’est plus le cas (sans doute des optimisations Apple pour améliorer l’autonomie). A la place j’utilise nmap qui reçoit une réponse environ toutes les 5 secondes (résultats très variable).

La commande à passer (plusieurs fois) est la suivante (peu import le port):

nmap « Adresse_IP_iPhone » -n -p 80

Le téléphone répondra de temps en temps (en faite si la requête a été faite lors de son slot d’écoute réseau)

Et le scripte complet (du bash toujours aussi mal codé, on va dire que c’est du legacy ;) )

#!/bin/bash
 
IPADDRESSCLEM="192.168.102.19"
SLEEPTIME=3
 
COUNTPRESENTCLEM=0
COUNTABSENTCLEM=0
 
while true
do
    DEVICECLEM=$(nmap "$IPADDRESSCLEM" -n -p 80 | grep "1 host up" && echo "On" || echo "Off")
 
    if [[ $DEVICECLEM != *'Off'* ]]
    then
    	COUNTPRESENTCLEM=$((COUNTPRESENTCLEM+1))
    else
    	COUNTABSENTCLEM=$((COUNTABSENTCLEM+1))
    fi
 
	if [[ "$COUNTPRESENTCLEM" = 1 ]]	# 1 confirmation is OK tu be sure Clement is here
	then
		curl --max-time 5 --connect-timeout 5 --header "Content-Type: text/plain" --request PUT --data "ON" http://openhab:8080/rest/items/Presence_Clement/state
		COUNTABSENTCLEM=0
		echo "$(date) - Clement est present"
	fi
 
	if [[ "$COUNTABSENTCLEM" = 40 ]]	# We need 40 confirmations (2min) to be sure Clement is really away
	then
		curl --max-time 5 --connect-timeout 5 --header "Content-Type: text/plain" --request PUT --data "OFF" http://openhab:8080/rest/items/Presence_Clement/state
        	COUNTPRESENTCLEM=0
        	echo "$(date) - Clement est absent"
	fi
 
        if [[ "$COUNTPRESENTCLEM" = 3 ]]        # 1 confirmation is OK tu be sure Clement is here
        then
                COUNTPRESENTCLEM=2
                COUNTABSENTCLEM=0
                echo "$(date) - Clement est toujours present"
        fi
 
    echo "$(date) - confirmation presence: $COUNTPRESENTCLEM"
    echo "$(date) - confirmation absence: $COUNTABSENTCLEM"
    sleep $SLEEPTIME
done