You are currently viewing Détection de présence en temps réel par Smartphone en Bluetooth Low Energy dans Jeedom

Détection de présence en temps réel par Smartphone en Bluetooth Low Energy dans Jeedom

Tags : Présence, Smartphone, Bluetooth, BLE, Beacon, Raspberry, Raspbian, Python, Linux

0. Contexte

Pouvoir automatiser pas mal de choses dans Jeedom grâce à la détection d’un ou de plusieurs téléphone(s) dans la maison ou juste dans une pièce. L’avantage ici est de pouvoir se passer de balises BLE encombrantes (même si de plus en plus minis) qui ne suivent pas toujours la personne car accrochées à un porte-clés et dont les batteries peuvent rendre l’âme sans le savoir.

Le BLE (Bluetooth Low Energy) n’utilise quasiment pas les batteries du téléphone et est donc une bonne solution par rapport au Wifi que l’on n’a pas forcément envie d’allumer toute la journée et surtout la nuit.

0.1 Les exemples d’utilisation

  • Activation/désactivation d’alarme.
  • Allumer les lampes de la maison dés le retour, éteindre les lampes restées allumées si plus personne.
  • Gestion des lumières dans la pièce où le smartphone se trouve (RSSI supérieur à X dBm) : si plus personne, on coupe.
  • Alerte si consommation d’eau alors que plus personne dans la maison.
  • Alerte si en dehors de la maison et qu’une porte, une fenêtre ou un volet est resté ouvert ou s’ouvre.
  • Lancer/Arrêter les enregistrements des caméras de surveillance.

1. Matériel nécessaire

1.1 Au – un Raspberry ou autre device compatible BLE avec réseau et pouvant exécuter du code Python.

Si l’on veut faire une détection par pièce, il faudra évidemment plusieurs Raspberry pour pouvoir faire une localisation d’un Smartphone grâce au niveau du signal reçu par chaque antenne BLE (triangulation).

Pour le tuto j’utilise des Raspberry Zero avec Raspbian Buster Lite et système root (/) en Read Only (https://github.com/vladbabii/raspberry_os_buster_read_only_fs) pour éviter les crash nombreux de carte SD en cas de coupure de courant par exemple. Ces mêmes Raspberry me servent partout dans la maison pour d’autres projets DIY avec Jeedom (Tutos à venir) et certains ont des caméras (avec Rpi-Cam-Web-Interface qui permet d’armer/désarmer depuis Jeedom les enregistrements sur mouvement quand absent)

1.2 Un ou des smartphone(s) Android avec l’application « Beacon Simulator » pour transformer le téléphone en Beacon (voir point suivant)

L’avantage de cette application sur Android est qu’elle peut tourner en background, en mode résilient : si le système a besoin de plus de ressources à un moment donné, il ne pourra pas tuer le processus et donc le smartphone donnera toujours sa présence.

Code de Beacon Simulator disponible librement : https://github.com/vhiribarren/beacon-simulator-android

L’équivalent de cette application doit exister sur Ios mais je n’ai pas testé. Si tel est le cas, je ne peux pas assurer que mon code Python soit compatible (à adapter donc).

2. Beacon : Kesako?

Un beacon Bluetooth (« balise » en français) est un petit boîtier physique appartenant à la grande famille des objets connectés, en anglais, Internet Of Things (IoT). Cette balise est un émetteur fonctionnant grâce à la technologie de communication sans fil Bluetooth. Dans le cas de beacons industriels la technologie utilisée est souvent le Bluetooth Low Energy (BLE).

D’un point de vu technique, le beacon Bluetooth émet à une fréquence régulière et à une certaine puissance des signaux (RSSI), définis comme des ondes radios qui peuvent être lues par des appareils ayant une connectivité Bluetooth tels qu’un smartphone, une tablette ou une passerelle BLE qui fait le plus souvent office de scanner.

Ces ondes radios vont permettre aux beacons de transmettre des données. Mais, à la différence des périphériques Bluetooth « grand public » tels que des enceintes, des écouteurs ou des montres connectées, la fonction principale d’un beacon est le transfert de petites données. En effet, les beacons vont pouvoir transmettre des données comme un numéro identifiant ou une niveau de batterie, mais ils ne pourront pas transmettre de musiques ou d’images.

Vous avez donc compris : le ou les smartphone(s) vont jouer le rôle de ces petits boîtiers « beacon » et le ou les Raspberry de « scanner » pour donner ensuite les informations à Jeedom. On aura donc au final l’information de présence ou absence des smartphones et les niveau des signaux RSSI en temps réel!

2.1 Les différents types de balises Beacon

2.1.1 Ibeacons

En 2013, Apple a sorti son iBeacon, qui a été intégré aux appareils Apple (Systèmes d’exploitation iOS). Il était destiné à envoyer des signaux d’identification uniques aux téléphones ou tablettes en approche ou à proximité. Ils ont été utilisés pour la navigation intérieure hors ligne. Le Ibeacons ne transmet qu’un paquet constitué de trois parties : Major, Minor et le UUID.

2.1.2 Eddystone

Deux ans plus tard (2015), Google a publié son BLE Eddystone beacon en tant que concurrent d’iBeacon. Malheureusement, la plate-forme de balises Google Eddystone a échoué trois ans plus tard, en 2018. Eddystone a été conçu pour prendre en charge tous les appareils Android, Compatibles BLE ainsi que les appareils iOS, et il a tous les outils officiels pour le faire. Il transmet 3 paquets : Eddystone-UID, Eddystone-URL, Eddystone-TML.

2.1.3 AltBeacon

Créé par Radius Network, cette balise ne favorise aucun fournisseur par rapport à l’autre. Il est basé sur du code open source, le rendant idéal pour tous ceux qui cherchent à personnaliser leurs solutions de balise.

3. Mise en place

3.1 Installation de l’application Beacon Simulator sur le Smartphone (à refaire sur d’autres téléphones éventuels)

3.1.1 Création de la balise Beacon

J’ai choisi de simuler un Ibeacon qui est la forme la plus simple et dont le UUID sera le numéro unique à scanner (il faudra donc le noter pour la suite)
Dans Simulateur, en bas à droite on ajoute un Ibeacon avec le +, on modifie la puissance de transmission à Elevé (tant qu’à faire)

Le reste des paramètres peuvent rester par défaut

3.1.2 Lancer la diffusion du Beacon en mode Résilient

3.2 Création de l’équipement virtuel dans Jeedom (à dupliquer si plusieurs téléphone)

Ce qui donne chez moi avec les widgets qui vont bien pour 2 smartphones et 5 antennes BLE (Raspberry) :

Les commandes à créer (ici pour 5 antennes BLE, à adapter chez vous) :

3.3 Mise en place du script python sur le Raspberry (à refaire sur d’autres Raspberry éventuels)

Voici le script Python à modifier et copier pour chez vous (voir plus bas). Il s’agit du code pour mon antenne « Chambre ».

# Installer pip3 : sudo apt-get install python3-pip
# Installer bluepy : sudo pip3 install bluepy


from bluepy.btle import Scanner, DefaultDelegate
import urllib.request


class ScanDelegate(DefaultDelegate):
        def __init__(self):
                DefaultDelegate.__init__(self)

        def handleDiscovery(self,dev,isNewDev,isNewData):
                if isNewDev:
                        print("Discovered Device" , dev.addr)
                elif isNewData:
                        print ("Received New Data from" , dev.addr)



#################

uuid_phone1="83c777ac242c4e268576eaa1d737abef"
uuid_phone2="6d7ceb86e08b4c77808bc4f4bc7a4f81"
#uuid_phone3=""

jeedom_ip_address="192.168.1.241"
jeedom_api_virtual="YDunq1vAOqluSTLDia4ES0ZlAMctBx2GRsPpaPTITCfepMCV0l5nB7YLcmPPtkcA"

jeedom_phone1_id_online=441
jeedom_phone1_id_rssi=442

jeedom_phone2_id_online=467
jeedom_phone2_id_rssi=468

#jeedom_phone3_id_online=xxx
#jeedom_phone3_id_rssi=xxx


#################



def loop():

 while True:

  try:

   scanner = Scanner().withDelegate(ScanDelegate())

   # Scan delay in seconds, 0 for continuous
   devices = scanner.scan(5.0)

   phone1online=0
   phone1rssi=-120

   phone2online=0
   phone2rssi=-120

#   phone3online=0
#   phone3rssi=-120
   

   for dev in devices:

     print ("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi))

     for (adtype, desc, value) in dev.getScanData():

       if desc == "Manufacturer":	
        print("  %s = %s" % (desc, value))

       if desc == "Manufacturer" and uuid_phone1 in value:
        phone1online=1
        phone1rssi=dev.rssi

       if desc == "Manufacturer" and uuid_phone2 in value:
        phone2online=1
        phone2rssi=dev.rssi

#       if desc == "Manufacturer" and uuid_phone3 in value:
#        phone3online=1
#        phone3rssi=dev.rssi
        

   try:

    if phone1online == 1:
     print("Smartphone1 detected! RSSI="+str(phone1rssi))                       
     urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone1_id_online)+"&value=1")     
    else:
     print("Smartphone1 not detected! RSSI="+str(phone1rssi))
     urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone1_id_online)+"&value=0")

    urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone1_id_rssi)+"&value="+str(phone1rssi))

    if phone2online == 1:
     print("Smartphone2 detected! RSSI="+str(phone2rssi))                       
     urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone2_id_online)+"&value=1")     
    else:
     print("Smartphone2 not detected! RSSI="+str(phone2rssi))
     urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone2_id_online)+"&value=0")

    urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone2_id_rssi)+"&value="+str(phone2rssi))

#    if phone3online == 1:
#     print("Smartphone3 detected! RSSI="+str(phone3rssi))                       
#     urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone3_id_online)+"&value=1")     
#    else:
#     print("Smartphone3 not detected! RSSI="+str(phone3rssi))
#     urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone3_id_online)+"&value=0")

#    urllib.request.urlopen("http://"+str(jeedom_ip_address)+"/core/api/jeeApi.php?apikey="+str(jeedom_api_virtual)+"&plugin=virtual&type=event&id="+str(jeedom_phone3_id_rssi)+"&value="+str(phone3rssi))

   except Exception as error:
    print("Jeedom not available ! ", error)

  except Exception as error:
   print("Scan error ! ", error)
   break


loop()

3.3.1 Installation de pip3

pip3 est l’installateur de paquets pour Python version 3.

sudo apt-get install python3-pip

3.3.2 Installation de bluepy

Il sagit du paquet Python pour faire l’interface avec le Bluetooth LE.

sudo pip3 install bluepy

3.3.3 Modification du script Python avec le(s) UUID et les bonnes URL Jeedom (IP+API Virtuelle+ID des commandes virtuelles)

A vous à le modifier pour chez vous : si seulement 1 smarphone il faut mettre en commentaire les variables jeedom_phone2_id_online et jeedom_phone2_id_rssi, les lignes phone2online=0 et phone2rssi=-120 ainsi que le bloc if desc == « Manufacturer » and uuid_phone2 in value: et if phone2online == 1:. Si 3 smartphones, décommenter les lignes s’y rapportant et si plus de 3 smartphones à vous de créer le code en copiant/collant ce qui existe en suivant la même logique.

Il faut bien entendu, attribuer vos valeurs aux variables en début de code :

uuid_phoneX est l’UUID de l’application Beacon Simulator sans « – » pour le Smartphone X
jeedom_ip_address l’IP de Jeedom (sans http(s))
jeedom_api_virtual est l’API du plugin virtuel que l’on peut trouver dans Jeedom : Réglages=>Système=>Configuration=>API

Remarque : il s’agit ici d’un jeedom de développement qui n’est pas sur Internet et dont la clé a été régénérée après la démo pour question de sécurité.

jeedom_phoneX_id_online est le numéro de la commande du virtuel pour la présence du smartphone X que j’ai appelé « Antenne Chambre » (car le script tourne sur le Raspberry de la chambre, à adapter si d’autres antennes) pour la démo et qui doit être de l’info Binaire
jeedom_phoneX_id_rssi est le numéro de la commande du virtuel pour le signal RSSI du smartphone X que j’ai appelé « RSSI Chambre » (car le script tourne sur le Raspberry de la chambre, à adapter si d’autres antennes) pour la démo et qui doit être de l’info Numérique

3.3.4 Tests

On lance le script en console de la manière suivante, vous aurez alors les informations à l’écran sur le scan et éventuellement les erreurs si votre Jeedom n’est pas joignable. Si votre smartphone n’est pas détecté il faudra revoir la procédure. Le script pour mon antenne Chambre est scannerchambre.py

sudo python3 scannerchambre.py

Voici ce que ça donne dans Jeedom pour ma part : simulation d’une entrée dans la maison, présence dans la maison et départ de la maison pour le Smartphone 1

3.3.5 Automatisation du script au démarrage du Raspberry dans crontab

sudo vi /etc/rc.local

Et juste avant exit 0 en ajoute celle ligne à adapter avec votre chemin et le nom que vous avez donné au script

!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

python3 /home/pi/python/scannerchambre.py &

exit 0

4. Conclusion

Cela fait plusieurs mois que j’utilise ce principe de détection de présence dans Jeedom et ça fonctionne très bien. Quand je reviens avec la voiture, à peine garé sur la cour que mes lampes s’allument partout. Juste pour le jardin où ça lâche, il faudrait une antenne plus balaise à l’extérieur.

Les seuls problèmes constatés : quand je mets le téléphone en charge de temps en temps la diffusion du Beacon s’arrête? Et aussi quand je connecte mon téléphone à un autre équipement Bluetooth ça peut poser problème. Mais par contre une fois connecté la diffusion continue sans soucis : mon smartphone est connecté en permence à ma montre et la diffusion du Beacon n’est pas interrompue.