Dans cet article, je vais vous montrer comment intégrer, comme périphérique virtuel sur la ZiBASE, un détecteur de mouvement connecté à un Raspberry Pi. Nous allons voir l’ensemble des étapes , depuis la connexion du détecteur (PIR) au RaspBerry Pi , la création du script python , la gestion du service pir et le scénario sur la ZiBASE qui va nous permettre d’alimenter un détecteur virtuel, qui pourra ensuite être intégré à une alarme Zibase ou être utilisé dans d’autres scénarios.
Pour l’installation du module, j’ai suivi l’excellent article en anglais de Matt Hawkins intitulé Cheap PIR Sensors and the Raspberry Pi – Part 1 dont je reprends les grandes lignes pour montrer comment brancher et faire fonctionner ce merveilleux petit module.
Le matériel nécessaire
Nous allons utiliser comme détecteur un module PIR 5V (Passive Infra Red) que l’on trouvera facilement dans une boutique en ligne pour quelques euros. Je l’ai personnellement trouvé pour $2.40 chez www.dx.com. Nous allons le connecter à un Raspberry Pi (dans mon cas, j’utilise un Raspberry Pi B+ qui tourne sous Linux Raspbian version Wheezy du 20/06/2014)
Branchement du module PIR
Voici un schéma représentant les trois sorties du module et leurs branchements sur les pattes GPIO sur Raspberry Pi. Le module a deux potentiomètres qui permettent d’ajuster ses performances. Un pour la sensibilité (Sx) et le second (Tx) pour le réglage du temps où la sortie (pin OUT) du module reste à 3V lors de la détection d’un mouvement.
Paquets requis pour la gestion GPIO du Raspberry Pi
Pour la bonne éxécution du script python, il est nécessaire auparavant d’installer les différents paquets suivants:
sudo apt-get install python-dev sudo apt-get install python-rpi.gpio sudo apt-get install python-requests
Le script Python
J’ai repris le script donné en exemple par Matt, et l’ai adapté afin qu’il puisse tourner comme daemon linux et qu’il envoie une requête http à la ZiBASE lors de la détection de mouvement.
Les fichiers sont disponibles au téléchargement sur le site https://github.com/onlinux/Raspberry-Pi-PIR. Vous pourrez y télécharger l’ensemble du projet:
pi@raspi $ wget https://github.com/onlinux/Raspberry-Pi-PIR/archive/master.zip pi@raspi ~ $ unzip master.zip Archive: master.zip b2cffd544e4ca4ec420723e08b7fb15508b8d83c creating: Raspberry-Pi-PIR-master/ extracting: Raspberry-Pi-PIR-master/README.md creating: Raspberry-Pi-PIR-master/logrotate.d/ inflating: Raspberry-Pi-PIR-master/logrotate.d/pir inflating: Raspberry-Pi-PIR-master/pir inflating: Raspberry-Pi-PIR-master/pir.py pi@raspi ~ $
#!/usr/bin/python
#
# pir.py
#
# Import required Python libraries
import time
import RPi.GPIO as GPIO
import requests
import logging
import signal
import sys
import threading
URL_ZIBASE = 'http://192.168.0.100/cgi-bin/domo.cgi?CMD=LM%2049'
MOTION_ALARM_DELAY = 60
logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s', filename='/var/log/pir.log',level=logging.DEBUG)
def handler(signum = None, frame = None):
logging.debug (' Signal handler called with signal '+ str(signum) )
time.sleep(1) #here check if process is done
logging.debug( ' Wait done')
sys.exit(0)
for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]:
signal.signal(sig, handler)
# Each request gets its own thread
class RequestThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
try:
result = requests.get(url = URL_ZIBASE)
logging.debug(" %s -> %s" % (threading.current_thread(), result))
except requests.ConnectionError, e:
logging.warning(' %s CONNECTION ERROR %s' % (threading.current_thread(), e) )
# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)
# Define GPIO to use on Pi
GPIO_PIR = 7
logging.info( "PIR Module Holding Time Test (CTRL-C to exit)")
# Set pin as input
GPIO.setup(GPIO_PIR,GPIO.IN)
Current_State = 0
Previous_State = 0
try:
logging.info('Waiting for PIR to settle ...')
# Loop until PIR output is 0
while GPIO.input(GPIO_PIR)==1:
Current_State = 0
logging.info(' Ready')
# Loop until users quits with CTRL-C
while True :
# Read PIR state
Current_State = GPIO.input(GPIO_PIR)
if Current_State==1 and Previous_State==0:
# PIR is triggered
start_time=time.time()
logging.info(' Motion detected!')
# Record previous state
Previous_State=1
RequestThread().start()
elif Current_State==0 and Previous_State==1:
# PIR has returned to ready state
stop_time=time.time()
elapsed_time=int(stop_time-start_time)
logging.info(" (Elapsed time : " + str(elapsed_time) + " secs)")
Previous_State=0
logging.info(' Going to sleep for %s seconds' % (MOTION_ALARM_DELAY))
time.sleep(MOTION_ALARM_DELAY)
logging.info(' Ready')
time.sleep(1)
finally:
logging.info( " Reset GPIO settings & Quit")
# Reset GPIO settings
GPIO.cleanup()
Le script dans les détails
Définition de la requête http vers la ZiBASE
URL_ZIBASE = 'http://192.168.0.100/cgi-bin/domo.cgi?CMD=LM%2049'
Nous définissons ici la requête http qui va être envoyée vers la zibase. Ma zibase a pour adresse IP sur mon réseau local (lan) 192.168.0.100. Il faudra bien sûr changer cette adresse et l’adapter à votre installation. Ensuite le paramètre CMD=LM 49 signifie ‘lancer l’exécution du scénario numéro 49’. Nous reviendrons plus tard sur cette notion de numéro de scénario lorsque nous aborderons la conception du scénario sur notre zibase.
Durée de latence entre deux détections ou MOTION_ALARM_DELAY
MOTION_ALARM_DELAY = 60
Je définis ici, la durée en secondes ou le détecteur ignorera la détection de nouveaux mouvements. Une minute par défaut. En fait cela permet surtout de soulager la taille de la log. Ici, il n’y a pas de notion de durée de vie de la batterie comme dans les détecteurs classiques autonomes, donc si on le souhaite on peut très bien définir ce paramètre égale à 1 mais je n’en vois vraiment pas l’intérêt.
Configuration de la log
logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s', filename='/var/log/pir.log',level=logging.DEBUG)
Nous définissons ici le nom du fichier log du daemon (/var/log/pir.log) ou tous les messages seront inscrits avec pour niveau d’information ‘DEBUG’.
Nous verrons plus tard, comment définir une entrée dans logrotate.d qui permet d’avoir une gestion des fichiers log automatisée.
Gestion des signaux envoyés au daemon
def handler(signum = None, frame = None):
logging.debug (' Signal handler called with signal '+ str(signum) )
time.sleep(1) #here check if process is done
logging.debug( ' Wait done')
sys.exit(0)
for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]:
signal.signal(sig, handler)
…
…
finally:
logging.info( " Reset GPIO settings & Quit")
# Reset GPIO settings
GPIO.cleanup()
Les signaux de terminaison de processus sont interceptés, ce qui permet à notre script de se terminer gracieusement et surtout de laisser une situation propre au niveau de la gestion des GPIO du Raspberry Pi ( appel à la commande GPIO.cleanup())
Notion de Thread
# Each request gets its own thread
class RequestThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
try:
result = requests.get(url = URL_ZIBASE)
logging.debug(" %s -> %s" % (threading.current_thread(), result))
except requests.ConnectionError, e:
logging.warning(' %s CONNECTION ERROR %s' % (threading.current_thread(), e) )
Nous allons lancer la requête http vers la Zibase dans un thread, ce qui permet à notre script de ne pas être bloquant lors d’un problème de connexion à la zibase (problème réseau ou zibase déconnectée). Il m’est arrivé de voir la connexion refusée par la zibase, peut être était-ce lors du reboot après enregistrement d’un nouveau périphérique. Si la requête n’était pas exécutée dans un thread, lors d’un problème de connexion, le daemon serait tué!
Boucle de gestion de la détection de mouvement
# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)
# Define GPIO to use on Pi
GPIO_PIR = 7
logging.info( "PIR Module Holding Time Test (CTRL-C to exit)")
# Set pin as input
GPIO.setup(GPIO_PIR,GPIO.IN)
Current_State = 0
Previous_State = 0
try:
logging.info('Waiting for PIR to settle ...')
# Loop until PIR output is 0
while GPIO.input(GPIO_PIR)==1:
Current_State = 0
logging.info(' Ready')
# Loop until users quits with CTRL-C
while True :
# Read PIR state
Current_State = GPIO.input(GPIO_PIR)
if Current_State==1 and Previous_State==0:
# PIR is triggered
start_time=time.time()
logging.info(' Motion detected!')
# Record previous state
Previous_State=1
RequestThread().start()
elif Current_State==0 and Previous_State==1:
# PIR has returned to ready state
stop_time=time.time()
elapsed_time=int(stop_time-start_time)
logging.info(" (Elapsed time : " + str(elapsed_time) + " secs)")
Previous_State=0
logging.info(' Going to sleep for %s seconds' % (MOTION_ALARM_DELAY))
time.sleep(MOTION_ALARM_DELAY)
logging.info(' Ready')
time.sleep(1)
Test du script
A ce stade le script est fonctionnel. Pour tester son fonctionnement, il faut lancer le script sous root (sudo) et visualiser la log dans un autre terminal.
Si vous bougez devant votre détecteur de mouvement vous verrez la log réagir.
Si vous tapez CTRL-C dans la fenêtre de lancement du script, dans la log, vous verrez que le signal a été intercepté et a permis au script de terminer proprement en envoyant son ordre GPIO.clean().
Elaboration du scénario sur la ZiBASE
Avant de créer un scénario, il faut créer un détecteur virtuel pour qu’il puisse remonter les alertes de notre module PIR connecté au Raspberry PI.
Création du détecteur virtuel
Nous devons créer un périphérique virtuel de catégorie détecteurs, type MS13 par exemple (détecteur de mouvement) . Indiquez le nom de votre choix ( pour moi ce sera PI-MOTION) et lui attribuer un identifiant radio. Cet identifiant radio fictif doit être sous la forme “CS suivi de 9 chiffres'” ex: CS123456789, pour ma part j’ai choisi CS123456787 car j’ai déjà 2 périphériques virtuels créés ( ouverture fenêtre et détecteur de présence pour mon PSM02 Philio) ensuite cliquez sur « Capture d’identifiant » puis enfin, cliquez sur « Sauvegarder » après avoir coché, bien sûr, la case « Visualiser sur les interfaces de l’utilisateur».
Nous avons à ce stade créer notre détecteur de présence virtuel. Nous devons maintenant l’alimenter et pour cela nous allons créer un scénario.
Création du scénario
Créez un nouveau scénario, donnez lui un nom ( pour moi ce sera PIR-MOTION-49) . Le nombre 49 correspond au numéro du scénario nouvellement créé. Pour connaître ce numéro qui nous est nécessaire lors de la requête http dans notre script python, une fois le scénario créé, cliquez sur le bouton “Tester le scénario”, vous verrez ensuite dans le suivi d’activité le déclenchement du scénario avec son numéro associé (pour moi c’est 49) entre parenthèses.
Une fois le numéro du scénario connu , nous pouvons construire l’url qui permettra à notre script pir.py de déclencher le scénario sur la ZiBASE.
Souvenez-vous, ligne 16 du script:
URL_ZIBASE = 'http://192.168.0.100/cgi-bin/domo.cgi?CMD=LM%2049'
Modifiez le numéro dans le fichier pir.py LM%20XX , avec pour XX= votre numéro de script.
Une fois cette étape effectuée, si vous exécutez le script sur le raspberry Pi, celui-ci doit déclencher le scénario sur la ZiBASE qui va alimenter notre détecteur virtuel, et nous pouvons visualiser sur l’interface le déclenchement d’une alerte, si vous bougez devant votre module PIR, bien sûr!
Création du service pir
Dans l’article qui suivra PART 2, nous allons voir comment déclarer notre script pir.py comme un service linux, et le paramètrer pour qu’il s’exécute automatiquement au reboot du Raspberry Pi, et aussi paramétrer la gestion de la log avec logrotate.
Oulala que c’est compliqué !!! pour un novice comme moi
Mais je vais essayer
Merci pour cet excellent partage d’infos et pour tout ce travail