par Anne-Laure DELPECH | 2 Avr 2017 | Electronique - domotique, Raspberry Pi
Le capteur DS18B20 est un capteur à coût réduit (10 € les 5 capteurs étanches avec câble de 1 mètre ou 8 € les 10 capteurs de base), qui utilise le protocole 1-wire. On peut connecter plusieurs capteurs DS18B20 en série sur un même port du Raspberry Pi. Nous allons voir ici comment connecter un seul thermomètre et en écrire la valeur dans un fichier txt par un script Shell ou PHP.
Connecter le capteur DS18B20
Une description détaillée du capteur DS18B20 est disponible en anglais ici. Le capteur peut mesurer des températures entre -55°C et +125°C et reste précis à 0.5°C sur l’intervalle -10°C à +85°C. Chaque capteur a un numéro de série unique (64 bits) et peut donc être identifié précisément.
Pour une seule sonde, on câble comme dans le schéma de droite (note du 29/12/2019 : ATTENTION, le schéma de droite est faux, le connecteur 1 est raccordé à GND, le connecteur 3 à VCC 3.3V !).
On peut mettre plusieurs capteurs en série (en théorie autant qu’on veut, en pratique il semble qu’il vaille mieux se limiter à 10 capteurs). Dans ce cas, on connecte une seule résistance 4.7 K et plusieurs sondes selon le schéma ci-dessous (note du 29/12/2019 : qui est juste, connecteur 1 raccordé à GND, 3 à VDD 3.3 V).
Paramétrer le Pi pour lire la / les températures
Editer /boot/config.txt
pour qu’il contienne la ligne suivante puis redémarrer le Pi :
dtoverlay=w1-gpio
Tester le/les capteurs
En ligne de commande, taper les lignes suivantes
sudo modprobe w1-gpio
sudo modprobe w1-therm
cd /sys/bus/w1/devices
ls
cd 28-xxxx (changer pour correspondre aux numéros de série qui s'affichent)
cat w1_slave
Si le capteur est correctement câblé, on voit apparaître quelque chose qui ressemble à ce qui suit, où t=20187
signifie que la température est 20.187°C :
43 01 4b 46 7f ff 0d 10 bd : crc=bd YES
43 01 4b 46 7f ff 0d 10 bd t=20187
S’il y a plus d’un capteur de température, ls
dans /sys/bus/w1/devices
affichera plusieurs répertoires.
Installer les drivers sur le Pi
modprobe w1-gpio
et modprobe w1-therm
sont les drivers pour les capteurs de température. Ils doivent démarrer lorsque le Pi démarre. Pour celà, ajouter les lignes suivantes à /etc/modules
:
w1‐gpio
w1‐therm
On redémarre le Pi et les drivers sont maintenant chargés.
Un script PHP pour lire les différentes températures
Noter que pour exécuter un script PHP en ligne de commande, il faut avoir préalablement installé PHP-CLI, avec la commande apt-get install php5-cli .
Le script read-temperature.php (exécutable) contient :
#!/usr/bin/env php
<?php
if (!defined("THERMOMETER_SENSOR_PATH")) {
define("THERMOMETER_SENSOR_PATH", "/sys/devices/w1_bus_master1/28-0000046766b0/w1_slave");
}
// Open resource file for thermometer
$thermometer = fopen(THERMOMETER_SENSOR_PATH, "r");
// Get the contents of the resource
$thermometerReadings = fread($thermometer, filesize(THERMOMETER_SENSOR_PATH));
// Close resource file for thermometer
fclose($thermometer);
// We're only interested in the 2nd line, and the value after the t= on the 2nd line
preg_match("/t=(.+)/", preg_split("/\n/", $thermometerReadings)[1], $matches);
$temperature = $matches[1] / 1000;
// Output the temperature
print $temperature . " °C. \n\r";
?>
On l’exécute avec la commande en ligne php read-temperature.php .
Dans mon cas, il affiche 20.875 ▒C.
Un script Shell pour lire la température
Voir ce projet, en anglais. Il lit plusieurs températures à la fois et les affiche à l’écran du Pi sous la forme 28-0000046766b0=20.937 .
Pour ma part, je n’ai qu’une seule température à lire et je veux l’écrire dans un fichier texte que j’enverrai ultérieurement à un serveur distant.
Je crée le script read-status.sh, (avec encodage UTF8 sans BOM, retours chariot UNIX et droits d’accès 744) qui contient :
#!/bin/bash
# afficher les variables d'environnement (utile pour un cron job)
printenv
# check my Hostname variable
ThisHost=$(hostname)
# Get UTC time
UtcNow= date -u
# There should be no ECHO in a CRON job, so comment this !
echo $ThisHost
# $1 is the variable appended to the file when executed
# example : ./send-status.sh essai would put "essai" in $1
# local file to write into
FILE=$ThisHost"-status.txt"
# local directory to write to file and pick it for upload
REPERTOIRE="/home/jf/temp/"
echo $REPERTOIRE$FILE
#Read last temperature
temperature=$(find /sys/bus/w1/devices/ -name "28-*" -exec cat {}/w1_slave \; | grep "t=" | awk -F "t=" '{print $2/1000}')
# create file and add content to it
cd $REPERTOIRE
cat > $FILE <<EOF # single > will empty and overwrite the file
pi hostname, time, statut, temperature
$ThisHost, $UtcNow, $1, $temperature
EOF
Attention, ce script ne lit que le dernier des capteurs de température.
On l’exécute avec la commande en ligne ./read-status.sh OK .
Dans le répertoire temp, j’ai maintenant un fichier piname-status.txt, qui contient :
pi hostname, time, statut, temperature
piname, Sun 2 Apr 15:01:44 CEST 2017, OK, 21.312
Et maintenant ?
Je peux lire la température mesurée par le Pi et la noter dans un fichier texte à chaque fois que j’exécute ./read-status.sh OK en commande en ligne.
La prochaine étape sera d’envoyer les informations du fichier texte à un serveur externe de manière automatique. J’ai déjà décrit l’utilisation d’un cron job dans l’article « Cron Job sur un hébergement mutualisé OVH » mais je vais le réaliser sur un Raspberry Pi. Cest l’objet de l’article « Raspberry Pi : envoyer en ftp un fichier à un serveur, par Cron Job ».
par Anne-Laure DELPECH | 17 Août 2016 | php
J’ai besoin de lire le contenu de fichiers créés par une application tierce. Il faut :
- lister les fichiers avec extension ‘log’ dans un répertoire ;
- pour chaque fichier, lire chaque ligne ;
- pour chaque ligne, transformer son contenu texte en un array de données ;
- selon la valeur de certains éléments de la ligne, réaliser une action spécifique ;
- une fois le fichier traité, en modifier l’extension (devient ‘fait’).
Pour cela, j’utilise un script PHP installé dans le répertoire /var/www/html/tests d’un Raspberry Pi sur lequel j’ai installé apache et PHP (cf article Un serveur Web sur mon Raspberry Pi).
De quoi je pars ?
/var/www/html/tests contient le fichier test-explode.php et un sous répertoire data .
/var/www/html/tests/data contient 3 fichiers dont le nom est sous la forme domoAL_20150910.log . Chacun de ces fichiers contient 1000 à 2000 lignes de type :
1441868688 ! Thu, 10 Sep 2015 07:04:48 GMT ! dev_0x05 ! 2756 2 1462 1831 1931 0
1441868744 ! Thu, 10 Sep 2015 07:05:44 GMT ! dev_0x05 ! 2761 2 1462 1825 1918 0
1441868799 ! Thu, 10 Sep 2015 07:06:39 GMT ! dev_0x05 ! 2756 2 1462 1825 1950 0
1441868854 ! Thu, 10 Sep 2015 07:07:34 GMT ! dev_0x05 ! 2760 2 1468 1831 1993 868
1441868910 ! Thu, 10 Sep 2015 07:08:30 GMT ! dev_0x05 ! 2754 2 1468 1843 2037 0
1441868965 ! Thu, 10 Sep 2015 07:09:25 GMT ! dev_0x05 ! 2762 2 1468 1856 2075 0
Lister les fichiers d’un répertoire
Objectif : lister les fichiers avec extension ‘log’ dans un répertoire.
Ma solution est fortement inspirée de cette page de php.net.
<section class="data">
<H3>Test list each file in a directory</h3>
<?php
// http://php.net/manual/fr/function.scandir.php
echo "<br /><hr />" ;
$directory = '../tests/data';
$file_read = array( 'log' );
$scanned_directory = array_diff( scandir( $directory ), array( '..', '.' ) );
foreach ( $scanned_directory as $key => $value ) {
$type = explode( '.', $value );
$type = array_reverse( $type );
if( !in_array( $type[0], $file_read ) ) { // continue if not ".log"
continue;
}
$lines = 0;
$handle = fopen( $directory . DIRECTORY_SEPARATOR . $value, 'r' );
while ( !feof( $handle ) ) {
if ( is_bool( $handle ) ) {
break;
}
$line = fgets( $handle );
$lines++;
}
fclose( $handle );
$result['lines_html'][] = array ( $directory . '/' . $value , $lines ) ;
$result['lines_count'] = $result['lines_count'] + $lines;
$result['files_count'] = $result['files_count'] + 1;
}
var_dump( $result ) ;
echo "<br /><hr />" ;
?>
</section>
ce script affiche un array sur ma page (que j’ai mis en forme à la main) :
array(3) {
["lines_html"]=> array(3) {
[0]=> array(2) {
[0]=> string(33) "../tests/data/domoAL_20150910.log"
[1]=> int(1561)
}
[1]=> array(2) {
[0]=> string(33) "../tests/data/domoAL_20150913.log"
[1]=> int(1560)
}
[2]=> array(2) {
[0]=> string(33) "../tests/data/domoAL_20150914.log"
[1]=> int(1560)
}
}
["lines_count"]=> int(4681)
["files_count"]=> int(3)
}
Le script trouve donc bien les 3 fichiers et le nombre de ligne de chaque fichier.
Lire les lignes d’un fichier
Objectif : pour chaque fichier, lire chaque ligne.
Créer un array avec la liste des fichiers
Je crée une fonction qui génère un array avec le nom de chaque fichier du répertoire.
<?php
// http://php.net/manual/fr/function.scandir.php
// list all log files in the ../tests/data directory in an array
$list_files = al_list_files_in_dir( '../tests/data', array( 'log' ) ) ;
echo "<br />liste des fichiers<hr />" ;
var_dump( $list_files ) ;
echo "<br /><hr />" ;
function al_list_files_in_dir( $directory, $file_read ) {
$scanned_directory = array_diff( scandir( $directory ), array( '..', '.' ) );
foreach ( $scanned_directory as $key => $value ) {
$type = explode( '.', $value );
$type = array_reverse( $type );
if( !in_array( $type[0], $file_read ) ) { // continue if not ".log"
continue;
}
$result[] = $directory . '/' . $value ;
}
return $result ;
}
?>
J’obtiens un array comme celui ci (mis en forme à la main) :
array(3) {
[0]=> string(33) "../tests/data/domoAL_20150910.log"
[1]=> string(33) "../tests/data/domoAL_20150913.log"
[2]=> string(33) "../tests/data/domoAL_20150914.log"
}
Dans chaque fichier, lire les lignes une à une
<H4>read each line of each log file</h4>
<?php
foreach ( $list_files as $key => $value ) {
$file_content = al_read_lines_in_file( $value ) ;
echo "<br />contenu des fichiers<hr />" ;
var_dump( $file_content ) ;
echo "<br /><hr />" ;
}
function al_read_lines_in_file( $file ) {
$handle = fopen( $file, "r" );
$count = 0 ;
if ($handle) {
while (($line = fgets($handle)) !== false) {
$content[] = $line ;
}
fclose($handle);
return $content ;
} else {
echo "can't open file \n" ;
}
}
?>
Affiche 3 gigantesques arrays de 1500 lignes chacun environ.
Mettre le contenu d’une ligne dans un array
Objectif : pour chaque ligne, transformer son contenu texte en un array de données.
Chaque ligne contient des données séparées soit par « ! », soit par une tabulation. Je veux la transformer en une série de données.
<H3>Store the content of each line in an array</h3>
<?php
foreach ( $list_files as $key => $value ) {
$file_content = al_read_lines_in_file( $value ) ;
$line_count = 0 ;
foreach ( $file_content as $contents => $content ) {
$file_data[ $line_count ] = al_store_lines_in_array( $content ) ;
$line_count++ ;
}
echo "<br />données" . $value . "<hr />" ;
var_dump( $file_data ) ;
echo "<br /><hr />" ;
}
function al_store_lines_in_array( $text ) {
$val = explode("!", $text);
// split on tabulation
$temp = preg_split( "/[\t]/", trim( $val[3] ) );
// strip whitespace from the beginning and end of string.
$val[0] = trim( $val[0] );
$val[1] = trim( $val[1] );
$val[2] = trim( $val[2] );
$val[3] = trim( $val[3] );
$val[4] = trim( $temp[0] );
$val[5] = trim( $temp[1] );
$val[6] = trim( $temp[2] );
$val[7] = trim( $temp[3] );
$val[8] = trim( $temp[4] );
$val[9] = trim( $temp[5] );
return $val ;
}
?>
Pour le fichier ../tests/data/domoAL_20150910.log , ça me donne un array de 1560 arrays sous forme :
array(1560) {
[0]=> array(10) {
[0]=> string(10) "1441843202"
[1]=> string(29) "Thu, 10 Sep 2015 00:00:02 GMT"
[2]=> string(8) "dev_0x05"
[3]=> string(23) "2755 2 1531 1906 2168 0"
[4]=> string(4) "2755"
[5]=> string(1) "2"
[6]=> string(4) "1531"
[7]=> string(4) "1906"
[8]=> string(4) "2168"
[9]=> string(1) "0"
}
...
}
tout est sous la forme de texte (string). Il va falloir maintenant que je transforme la date « 1441843202 » et la dernière valeur (0 pour la ligne affiché ci-dessus) en données sur lesquelles je pourrai valider ou non une condition.
Mettre des conditions sur le contenu de l’array
Objectif : selon la valeur de certains éléments de la ligne, réaliser une action spécifique. Si le dernier élément de l’array n’est pas nul, l’afficher avec sa date. Si le temps écoulé depuis le dernier élément affiché est supérieur à 15 minutes, afficher la ligne même si sa dernière valeur est nulle.
conditions sur deux données
Je crée un array contenant des données comme celles qui doivent être produites par la lecture d’un des fichiers log. Je transforme les deux données sur lesquelles je veux pouvoir faire une condition en entiers avec la fonction intval() .
Pour le timestamp, je veux qu’il puisse être affiché de manière lisible : $date_humain = date ( « d/m/Y H:i:s » , $date_stamp ) ; va transformer 1441843313 en 10/09/2015 02:01:53 .
Le script suivant lit le contenu de l’array de données puis :
- si la dernière valeur ($value[9] ) est nulle, met $save à faux, sauf si ça fait plus de 5 minutes que $save est faux.
- si $save est true, imprime les données
Vu l’array que j’ai construit pour cet essai, je devrais avoir 4 lignes imprimées et une non (celle qui correspond à la deuxième valeur de l’array, qui a un timestamp très proche du premier).
<H3>Test conditions sur éléments de l'array de données</h3>
<?php
$data = array (
0 => array(
0 => "1441843202" ,
1 => "Thu, 10 Sep 2015 00:00:02 GMT" ,
2 => "dev_0x05" ,
3 => "2755 2 1531 1906 2168 0" ,
4 => "2755" ,
5 => "2" ,
6 => "1531" ,
7 => "1906" ,
8 => "2168" ,
9 => "0"
),
1 => array(
0 => "1441843258" ,
1 => "Thu, 10 Sep 2015 00:00:58 GMT" ,
2 => "dev_0x05" ,
3 => "2761 2 1537 1906 2137 0" ,
4 => "2761" ,
5 => "2" ,
6 => "1537" ,
7 => "1906" ,
8 => "2137" ,
9 => "0"
),
2 => array(
0 => "1441843313" ,
1 => "Thu, 10 Sep 2015 00:01:53 GMT" ,
2 => "dev_0x05" ,
3 => "2761 2 1537 1906 2137 0" ,
4 => "2761" ,
5 => "2" ,
6 => "1537" ,
7 => "1906" ,
8 => "2137" ,
9 => "216"
),
3 => array(
0 => "1441849352" ,
1 => "Thu, 10 Sep 2015 01:42:32 GMT" ,
2 => "dev_0x05" ,
3 => "2761 2 1537 1906 2137 0" ,
4 => "2761" ,
5 => "2" ,
6 => "1537" ,
7 => "1906" ,
8 => "2137" ,
9 => "0"
),
4 => array(
0 => "1441851457" ,
1 => "Thu, 10 Sep 2015 02:17:37 GMT" ,
2 => "dev_0x05" ,
3 => "2761 2 1537 1906 2137 0" ,
4 => "2761" ,
5 => "2" ,
6 => "1537" ,
7 => "1906" ,
8 => "2137" ,
9 => "51"
)
) ;
// var_dump( $data ) ;
// echo "<hr /><br />" ;
echo "<hr />" ;
$ref_time = 0000000 ;
foreach ( $data as $key => $value ) {
$date_stamp = intval( $value[0] ) ;
$date_humain = date ( "d/m/Y H:i:s" , $date_stamp ) ;
$time_lapsed = $date_stamp - $ref_time ; // temps écoulé depuis dernière ligne à imprimer
$chaudiere = intval( $value[9] ) ;
if ( $chaudiere == 0 ) {
$save = false ;
if ( $time_lapsed > 300 ) { // plus de 5 minutes
$save = true ;
$ref_time = $date_stamp ;
}
echo "<hr />" ;
} else {
$save = true ;
}
echo $key . " | \t" . $time_lapsed . " | \t" ;
if ( $save == true ) {
echo $chaudiere . " | \t" . $save . " | \t" . $date_stamp . " | \t" . $date_humain ;
} else {
echo "do not print" ;
}
echo "<hr />" ;
}
echo "<br />" ;
?>
et le résultat est conforme à mes attentes :
Modifier l’extension d’un fichier
Objectif : une fois le fichier traité, en modifier l’extension (devient ‘fait’).
ici j’ai fait beaucoup usage de /var/log/apache2/error.log !!! J’ai ainsi compris que j’obtenais une erreur « Permission denied » lorsque je voulais renommer.
Je n’ai jamais réussi à réaliser l’opération, même en la remplaçant par une copie puis une suppression du fichier initial… Puis, j’ai eu l’idée que c’est normal ! Heureusement que l’on ne peut pas supprimer ou renommer des fichiers au travers d’un navigateur internet…
j’ai donc créé un fichier test-rename.php (droits 740) dans le répertoire /home/jf/exec du Raspberry Pi. Dans le répertoire /home/jf/snd/data, j’ai placé les 3 fichiers à renommer. Et ça fonctionne !
#!/usr/bin/php
<?php
$directory = '/home/jf/snd/data';
$file_read = array( 'log' );
$scanned_directory = array_diff( scandir( $directory ), array( '..', '.' ) );
foreach ( $scanned_directory as $key => $value ) {
$type = explode( '.', $value );
// var_dump( $type ) ;
$type = array_reverse( $type );
if( !in_array( $type[0], $file_read ) ) { // continue if not ".log"
continue;
}
$old_name = $directory . DIRECTORY_SEPARATOR . $value ;
$new_name = $directory . DIRECTORY_SEPARATOR . $type[1] . ".fait" ;
$return_val = rename( $old_name, $new_name );
if ( $return_val == 1 ) {
echo "success : " . $old_name . " renamed " . $new_name . "\r\n";
} else {
echo "failed to rename " . $old_name . " to : " . $new_name . "\r\n" ;
}
}
?>
Ensuite dans la console de commande du Raspberry Pi :
cd /home/jf/exec
./test-rename.php
Et ça y est, la console affiche
success : /home/jf/snd/data/domoAL_20150910.log renamed /home/jf/snd/data/domoAL_20150910.fait
success : /home/jf/snd/data/domoAL_20150913.log renamed /home/jf/snd/data/domoAL_20150913.fait
success : /home/jf/snd/data/domoAL_20150914.log renamed /home/jf/snd/data/domoAL_20150914.fait
Et si je vérifie, les 3 fichiers ont bien été renommés.
Et maintenant ?
J’ai fait fonctionner les prototypes de code dont je vais avoir besoin. Je vais les utiliser pour faire échanger des données entre un Raspberry Pi (qui contient les fichiers log) et une box domotique qui va archiver et afficher les données.
par Anne-Laure DELPECH | 4 Juil 2016 | Raspberry Pi
Dans l’article précédent de cette série Caméra de surveillance et Raspberry Pi, j’indiquais que motion crée beaucoup d’images et vidéos qui ne correspondent pas à de véritables mouvements devant la caméra.
motion permet de nombreux réglages. Je l’ai choisi pour ça. En particulier, il semble efficace pour éliminer les mouvements liés au vent.
Pour comprendre les différents réglages, il faut lire attentivement cette aide (en anglais) sur les réglages de la détection de mouvement avec motion.
La situation initiale
Dans /etc/motion/motion.conf , j’ai entre autres les réglages suivants :
# Je ne comprends pas comment ça fonctionne. Valeur par défaut = EedDl
despeckle_filter EedDl
# Ignore les changements soudains de lumière - de 0 (arrêt) à 100%.
lightswitch 0
# Smartmask est un masque auto-apprenant qui va bloquer la détection dans les endroits de l'image où il y a des mouvements fréquents, comme des branches qui bougent à cause du vent. 0 (off) à 10 rapide.
smart_mask_speed 0
# nombre minimum de photos avec du mouvement avant détection : defaut 1 : tous mouvements détectés.
minimum_motion_frames 1
# base pour déclarer un mouvement. C'est le nombre de pixels changés après le filtrage du bruit, le masque et le "despeckle".
threshold 1500
# réglage automatique du threshold - ne fonctionne pas
threshold_tune off
# niveau de "bruit" pour distinguer le bruit de la caméra d'un mouvement
noise_level 32
# si on, ajustement automatique du bruit
noise_tune off
Avec ce réglage, j’obtiens (sur une journée avec du vent) beaucoup trop de faux positifs.
Les faux positifs contiennent du « bruit » la nuit, l’éclairage de la lampe à côté de la caméra, et des mouvements liés au vent :
« bruit » la nuit
Réglages du 1er juillet – soir
J’ai modifié le niveau de lumière qui déclenche un mouvement, le nombre d’images modifiées avant la détection de mouvement, le ‘theshold’ et le niveau de bruit.
despeckle_filter EedDl
lightswitch 25
smart_mask_speed 5
minimum_motion_frames 3
threshold 3000
noise_level 100
noise_tune off
Nota : après chaque réglage de motion.conf, il faut redémarrer le service motion avec :
service motion restart
Le 2 juillet, de 0h à 14h (heure du réglage suivant, il n’y a eu que 24 fichiers créés ( 1 Mo) et 24 fichiers correspondent à un mouvement effectif (ma voiture qui part puis qui revient).
Mais la caméra ne détecte pas une personne qui se déplace à pied.
Réglages du 2 juillet – 11h45
Je n’ai corrigé que le « threshold ».
despeckle_filter EedDl
lightswitch 25
smart_mask_speed 5
minimum_motion_frames 3
threshold 1500
noise_level 100
noise_tune off
Pendant la journée tout va bien : pas de fausse détection (mais le système ne détecte toujours pas une personne à pied) mais la nuit, il y a eu plein de faux positifs. Dès que le jour s’est levé, il n’y a plus de souci.
Réglages du 3 juillet – détecter une personne à pied
Pour détecter une personne à pied, j’ai modifié les paramètres suivants successivement jusqu’à ce que je déclenche une détection de mouvement :
minimum_motion_frames 1
noise_level 32
smart_mask_speed 10
motion : détection d’une personne
Ce n’est qu’au dernier changement que j’ai détecté le mouvement d’une personne.
Ces paramètres détectent aussi bien une voiture qu’une personne (12h20 = OK) :
despeckle_filter EedDl
lightswitch 25
smart_mask_speed 10
minimum_motion_frames 3
threshold 1500
noise_level 32
noise_tune off
Je laisse les paramètres suivants en l’état :
despeckle_filter EedDl
lightswitch 25
smart_mask_speed 10
minimum_motion_frames 3
noise_tune off
et j’étudie l’impact de changements sur threshold ou noise_level :
Threshold |
Noise_level |
Détecte ? |
1500 |
100 |
12h42 ne me détecte pas et fait un faux positif |
3000 |
32 |
12h26 ME détecte = OK |
3000 |
100 |
12h34 NON, ne me détecte pas |
Les réglages suivants sont donc satisfaisants :
despeckle_filter EedDl
lightswitch 25
smart_mask_speed 10
minimum_motion_frames 3
threshold 3000
noise_level 32
noise_tune off
Maintenant reste à faire un bilan sur environ 24h (depuis 13h le 3 juillet) :
- détection d’une personne : Oui
- détection d’une voiture : oui
- faux positifs : 2 en une nuit.
Je considère donc que ces réglages sont corrects.
Autres notes :
On peut mettre motion en mode deboguage pour voir comment se passe la détection : voir cette page sur le wiki de motion.
par Anne-Laure DELPECH | 3 Juil 2016 | Raspberry Pi
Mon objectif est maintenant de transformer le Raspberry Pi qui gère les caméras avec motion en un serveur web qui publie une page web contenant les flux vidéos. (suite…)
par Anne-Laure DELPECH | 3 Juil 2016 | Raspberry Pi
Dans cet article de la série Caméra de surveillance et Raspberry Pi, nous allons transformer une vieille tablette android en caméra IP dont le flux sera suivi par un Raspberry Pi, avec motion. Nous verrons aussi comment configurer motion pour qu’il suive deux caméras.
transformer une tablette android en caméra IP
Ma tablette est une Samsung Galaxy tab 7.7 (GT-P6210) équipée d’android 4.0.4. Elle n’est plus utilisable comme tablette car sa batterie ne tient plus. Je l’ai changé mais la nouvelle batterie n’a pas duré longtemps. Je vais donc alimenter en permanence cette tablette, l’accrocher à un mur d’où elle filmera le couloir. La détection de présence sera assurée par motion, sur le Raspberry Pi qui gère déjà le flux d’une caméra IP extérieure.
J’ai essayé de mettre une version plus récente d’android sur la tablette mais je n’ai pas réussi. Je reste donc en version 4.0.4.
Pour transformer la tablette en caméra IP, c’est très simple :
- installer (via google play) l’application gratuite IP Webcam
- Régler l’application :
- Main camera : front camera
- motion and sound detection : « disable » pour tout
- connection settings : port 8090, login/password not set
- cloud streaming : off
Quand les réglages sont faits, tout en bas : Service Control / start server : lance le serveur de la caméra IP.
Et voilà, maintenant si je tape « http://192.168.1.17:8090/video » dans un navigateur, j’ai accès au flux vidéo de la tablette. Et avec « http://192.168.1.17:8090 « , je vois un écran de réglage.
Donner une adresse IP fixe à la tablette
J’ai trouvé la solution ici (en anglais).
Appuyer sur le réseau wifi auquel on est connecté puis choisir « avancé ». Si l’on règle sur IP statique au lieu de DHCP, on peut entrer l’adresse fixe (pour moi 192.168.1.202).
Selon cette page (en anglais), “Network Prefix length” correspond au « Masque de sous-réseau IP » de notre routeur. « 255.255.255.0 » est entré comme « 24 ». « 255.255.0.0 » comme « 16 ». Pour moi c’est bien 24 qui doit figurer dans cette case.
On vérifie : « http://192.168.1.202:8090/video » permet bien de visualiser le flux vidéo de notre tablette.
NOTA : pour que le flux vidéo ait la bonne adresse, il faut redémarrer la tablette une fois.
Réglage de motion sur le Raspberry Pi pour gérer deux caméras
La configuration de motion est faite avec etc/motion/motion.conf lorsqu’il y a une seule caméra. Mais lorsqu’il y en a plusieurs, il faut créer plusieurs configurations. Le principe général (cf wiki de motion) est de laisser motion.conf avec les réglages communs à toutes les caméras et créer des fichiers distincts, nommés threadX.conf , pour chaque caméra (X est le numéro de caméra).
- Créer les fichiers thread0.conf et thread1.conf , avec droits 664.
- A la fin de motion.conf, décommenter les lignes qui y font référence.
thread /etc/motion/thread0.conf
thread /etc/motion/thread1.conf
; thread /etc/motion/thread2.conf
- dans motion.conf, identifier les lignes qui sont spécifiques à chaque caméra et les copier dans un éditeur de texte. On peut les laisser telles quelles puisqu’elles seront moins prioritaires que les instructions spécifiques des fichiers threadX.conf.
- Dans chaque fichier threadX.conf, insérer les lignes spécifiques et faire les réglages.
Mon fichier thread1.conf contient :
# caméra galaxy tab 7.7 GT-P6210
# thread1.conf
videodevice /dev/video1
netcam_url http://192.168.1.202:8090/video
############################################################
threshold 3000
threshold_tune off
noise_level 32
noise_tune off
despeckle_filter EedDl
smart_mask_speed 10
lightswitch 25
minimum_motion_frames 3
############################################################
# Target base directory for pictures and films
target_dir /home/jf/motion/galaxy
snapshot_filename g-%v-%Y%m%d%H%M%S-snapshot
picture_filename g-%v-%Y%m%d%H%M%S-%q
movie_filename g-%v-%Y%m%d%H%M%S
timelapse_filename g-%Y%m%d-timelapse
############################################################
stream_port 8082
webcontrol_port 8086
Le fichier thread0.conf contient les mêmes lignes avec les paramètres que j’avais réglé dans les articles précédents de cette série Caméra de surveillance et Raspberry Pi. Evidemment stream_port et webcontrol_port sont différents (respectivement 8081 et 8085).
Redémarrer le service motion avec
service motion restart
Et maintenant les deux adresses http://nautilus:8082/?action=stream et http://nautilus:8081/?action=stream affichent le flux capturé de chacune des deux caméras par le Pi nautilus.
La caméra de la vieille tablette détecte bien les mouvements et stocke les fichiers générés dans le répertoire /home/jf/motion/galaxy . Idem pour la caméra 0 (foscam extérieure).
Modifier le cron de suppression de vieux fichiers
Maintenant au lieux de supprimer les vieux fichiers de /home/jf/motion, il faut supprimer dans /home/jf/motion/foscam et /home/jf/motion/galaxy.
Je modifie donc /home/jf/exec/camera–delete–cron.sh qui contient maintenant :
#!/bin/bash
# efface les fichiers avi et jpg de plus de deux jours
find /home/jf/motion/foscam -maxdepth 1 -name '*.avi' -type f -mtime +2 -exec rm {} \;
find /home/jf/motion/foscam -maxdepth 1 -name '*.jpg' -type f -mtime +2 -exec rm {} \;
find /home/jf/motion/galaxy -maxdepth 1 -name '*.avi' -type f -mtime +2 -exec rm {} \;
find /home/jf/motion/galaxy -maxdepth 1 -name '*.jpg' -type f -mtime +2 -exec rm {} \;
Mise en veille de la tablette
La tablette se met en veille (l’écran est noir). Mais si les réglages de gestion d’énergie de l’application IP Webcam sont comme sur la copie d’écran ci-dessous (aucune option n’est cochée), la caméra va continuer à travailler même si l’écran est noir.
Et maintenant ?
Il faudra que je règle la détection de mouvement de la tablette lorsque je l’aurai mise à sa place définitive. En attendant, elle a les mêmes réglages que ceux de la caméra extérieure. D’autres articles de la série Caméra de surveillance et Raspberry Pi sont également disponibles.
Enfin, si vous souhaitez visualiser le flux de la caméra de cette tablette, il suffit de taper http://nautilus:8082/?action=stream dans n’importe quel navigateur d’un appareil connecté au réseau local.
Moi, j’ai décidé de voir les deux caméras et d’autres informations sur une page « dashboard » et j’ai créé une application android qui permet de la visualiser et d’interdire l’extinction de l’écran de la tablette sur laquelle elle est utilisée. Si ça vous intéresse, c’est ici : Une application android pour afficher une page web d’un Raspberry Pi.
Commentaires récents