par Anne-Laure DELPECH | 17 Août 2016 | Non classé
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 | 15 Août 2016 | Eedomus, Raspberry Pi
Dans ce second article de la série Un tableau de bord domotique, je veux afficher une température stockée dans ma box domotique Eedomus + à mon tableau de bord (en PHP, sur Raspberry Pi).
Cet article a été complété le 8 mai 2017.
De quoi je pars ?
d’une page index.php servie par un Raspberry Pi, comme indiqué dans le premier article de cette série.
l’API de la box Eedomus
Elle est bien documentée ici : API eedomus.
Obtenir une clé d’API Eedomus
Dans https://secure.eedomus.com/, cliquer sur configurer puis « mon compte ».
- Cocher la case « autoriser l’API via http » et « sauver ».
- Cliquer sur « consulter vos identifiants »

On obtient ainsi les valeurs de api_user et api_secret qui nous permettront de nous connecter. On accède aussi à un formulaire qui va nous permettre de construire la requête.
Faire une requête pour un capteur spécifique
J’utilise le formulaire précédent puis je copie la requête HTTP obtenue :

La requête est de type (remplacer api_user et api_secret) :
http://api.eedomus.com/get?api_user=xxx&api_secret=yyy&action=periph.caract&periph_id=166280
Lorsque je la tape dans un navigateur internet, j’obtiens la chaîne JSON suivante :
{ "success": 1, "body":{"periph_id": "166280", "name": "Nest - Température Couloir RdC", "last_value": "24.5", "last_value_text": "", "last_value_change": "2016-08-15 15:50:55"}}
Pour lire cette donnée dans mon fichier PHP, je me suis inspirée de l’exemple donné à la fin du document API eedomus.
J’ai intégré le code suivant à ma page index.php :
<h3>Autres informations</h3>
<?php include 'eedomus.php';?>
<!-- nest temperature ID 166280 -->
<p>couloir : <?php echo al_get_eedomus_value( 166280, 'last_value' ) ; ?> °C</p>
Et dans le fichier eedomus.php , j’ai intégré une fonction al_get_eedomus_value :
<?php
// définition des variables
$api_user = 'xxx'; // a récupérer sur votre compte eedomus
$api_secret = 'yyy'; // a récupérer sur votre compte eedomus
/******************************************************************
* appel de l'API eedomus en PHP pour récupérer une donnée
*
* $id = 166280
* $val = 'last_value'
* retournera la température actuellement mesurée par le thermostat Nest
*
*****************************************************************/
function al_get_eedomus_value( $id, $val ) {
global $api_user ;
global $api_secret ;
// construction de l'URL de l'API
$url = "http://api.eedomus.com/get?action=periph.caract";
$url .= "&api_user=" . $api_user;
$url .= "&api_secret=" . $api_secret;
$url .= "&periph_id=" . $id;
// appel de l'API
$result = file_get_contents($url);
// on controle le résultat
if (strpos($result, '"success": 1') == false)
{
echo "Une erreur est survenue : [".$result."]";
}
else
{
$result = json_decode( $result, true ) ; // true transforme $result en un array
$retour = $result['body'][$val];
return $retour ;
}
}
Le résultat est maintenant affiché sur mon tableau de bord :

Mais les données ne sont mises à jour que si je rafraichis le tableau de bord manuellement.
Mettre à jour automatiquement les données de la page PHP
Cette question sur StackOverflow explique comment recharger une page toutes les 30 secondes. Il suffit d’ajouter <meta http-equiv= »refresh » content= »30″ /> en haut de la page PHP.
Comme 15 minutes = 900 secondes, j’ai intégré la ligne <meta http-equiv= »refresh » content= »900″ /> en haut de ma page PHP. Le haut contient donc maintenant :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Nautilus</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="A-style.css" rel="stylesheet" media="all" type="text/css">
<meta http-equiv="refresh" content="900" />
</head>
Complément (8 mai 2017)
J’ai affiné le contenu de ma page php pour avoir automatiquement la liste des périphériques de l’eedomus. C’est un préalable à un tableau de bord qui lirai automatiquement toutes les données de l’eedomus.
Obtenir la liste des périphériques
Dans le code ci-dessous, la fonction eedomus_url génère les url correctes pour :
- vérifier qu’on se connecte correctement à la box Eedomus ;
- Obtenir la liste des périphériques de la box Eedomus ;
- Lire la valeur d’un périphérique donné de la box Eedomus
la fonction ald_decode_french permet de lire correctement des textes encodés en français, avec des caractères spéciaux.
<?php
function eedomus_url( $action, $user_id, $pw ) {
/*
* eedomus_url( "&action=auth.test", $ee_apiuser, $ee_passwd ) construit
* https://api.eedomus.com/get?api_user=USER&api_secret=SECRET&action=auth.test
* eedomus_url( "&action=periph.list", $ee_apiuser, $ee_passwd ) construit
* https://api.eedomus.com/get?api_user=USER&api_secret=SECRET&action=periph.list
* eedomus_url( "&action=periph.caract&periph_id=156595", $ee_apiuser, $ee_passwd ) construit
* https://api.eedomus.com/get?api_user=USER&api_secret=SECRET&action=periph.caract&periph_id=156595
*
* ces 3 url renvoient bien une info en Json, en provoenance de l'eedomus dans un navigateur
*/
$eedomus_get = "https://api.eedomus.com/get?api_user=" ;
$eedomus_get .= $user_id ;
$eedomus_get .= "&api_secret=" ;
$eedomus_get .= $pw ;
$eedomus_get .= $action ;
return $eedomus_get ;
}
$ee_test = eedomus_url( "&action=auth.test", $ee_apiuser, $ee_passwd ) ;
$ee_list = eedomus_url( "&action=periph.list", $ee_apiuser, $ee_passwd ) ;
$ee_156595 = eedomus_url( "&action=periph.caract&periph_id=156595", $ee_apiuser, $ee_passwd ) ;
function ald_decode_french( $string ) {
$contents = utf8_encode( $string );
$results = json_decode( $contents );
return $results ;
}
Si j’utilise la fonction ald_decode_french sans la partie ‘utf8_encode’, le résultat est vide car les accents provoquent des erreurs. Ci-dessous, dans l’image, à gauche on a le résultat de <pre><?php print_r ( file_get_contents( $ee_list ) ) ; ?> </pre> et à droite le résultat de <pre><?php print_r ( ald_decode_french( file_get_contents( $ee_list ) ) ); ?> </pre> . Les accents sont correctement restitués dans la version de droite.

Et maintenant ?
Je vais maintenant voir comment un Raspberry Pi peut transmettre une valeur mesurée à l’Eedomus. Ce sera l’objet du prochain article de cette série Un tableau de bord domotique. Ensuite, je pourrai utiliser le présent tutoriel pour l’afficher sur mon tableau de bord.
par Anne-Laure DELPECH | 15 Août 2016 | Raspberry Pi
Aujourd’hui, je veux lire des données issues d’une station météo proche de chez moi via l’API wunderground. Je souhaite qu’elles s’affichent automatiquement dans mon tableau de bord domotique (une page PHP servie par un Raspberry Pi).
De quoi je pars ?
J’ai réglé un Raspberry Pi pour servir une page PHP qui affiche le flux de deux caméras de surveillance (voir l’article Récapitulatif : Raspberry Pi, motion et deux caméras).
Maintenant, je veux ajouter des données issues de capteurs externes ou non. Je commence par insérer des données issues d’une station météo externe, via l’API de wunderground.
Une API ?
J’ai suivi le très bon cours en ligne sur les API de Emily REESE, sur OpenClassRoom ici.
Une API, ou « Application Programming Interface », est une interface entre un utilisateur et une application. Un menu constitue l’API d’un restaurant par exemple. En informatique, lorsqu’on parle d’API, on parle en général d’API REST (cf sur wikipedia). Elles utilisent des instructions HTTP.
En général les requêtes HTTP à des API REST obtiennent une réponse en JSON (cf sur wikipedia).
L’API de wunderground
Wunderground est un site qui met à disposition des informations météos. Les personnes qui possèdent une station météo peuvent lui communiquer des données. On a ainsi accès à des données très locales.
J’ai identifié une station locale à Plonéour-Lanvern. Je veux en extraire des données.
Je me suis créé un compte sur Wunderground et j’ai généré une clé API : voir cet article en français pour savoir comment faire.
Avec la console apigee intégrée à wunderground ici, j’ai pu déterminer que la requête est sous la forme :
http://api.wunderground.com/api/APIkey/conditions/q/pws:Station-ID.json
avec APIkey qui est ma clé API (elle ressemble à « b8e924a8f008b81e« ) et Station-ID est égale à « IPLONOUR3 » pour la station qui m’intéresse. On obtient l’ID de la station en cliquant sur le nom de la station (flèche rouge dans la copie d’écran ci-dessous). j’accède alors à une page dont l’adresse est https://www.wunderground.com/personal-weather-station/dashboard?ID=IPLONOUR3#history. J’ai donc l’ID.

Faire une requête en PHP
Je me suis inspirée de cette question sur StackOverflow pour créer ma requête.
Si je met http://api.wunderground.com/api/APIkey/conditions/q/pws:IPLONOUR3.json (remplacer APIkey par votre clé API) dans un navigateur web, j’obtiens en retour une chaîne JSON :
{
"response": {
"version":"0.1",
"termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
"features": {
"conditions": 1
}
}
, "current_observation": {
"image": {
"url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png",
"title":"Weather Underground",
"link":"http://www.wunderground.com"
},
"display_location": {
"full":"Ploneour-Lanvern, France",
"city":"Ploneour-Lanvern",
"state":"",
"state_name":"France",
"country":"FR",
"country_iso3166":"FR",
"zip":"00000",
"magic":"34",
"wmo":"07201",
"latitude":"47.900333",
"longitude":"-4.287129",
"elevation":"60.00000000"
},
"observation_location": {
"full":"Rue François de Châteaubriand, Plonéour-Lanvern, ",
"city":"Rue François de Châteaubriand, Plonéour-Lanvern",
"state":"",
"country":"FR",
"country_iso3166":"FR",
"latitude":"47.900333",
"longitude":"-4.287129",
"elevation":"206 ft"
},
"estimated": {
},
"station_id":"IPLONOUR3",
"observation_time":"Last Updated on August 15, 3:01 PM CEST",
"observation_time_rfc822":"Mon, 15 Aug 2016 15:01:45 +0200",
"observation_epoch":"1471266105",
"local_time_rfc822":"Mon, 15 Aug 2016 15:04:53 +0200",
"local_epoch":"1471266293",
"local_tz_short":"CEST",
"local_tz_long":"Europe/Paris",
"local_tz_offset":"+0200",
"weather":"Clear",
"temperature_string":"79.9 F (26.6 C)",
"temp_f":79.9,
"temp_c":26.6,
"relative_humidity":"48%",
"wind_string":"Calm",
"wind_dir":"NE",
"wind_degrees":50,
"wind_mph":0.6,
"wind_gust_mph":"5.0",
"wind_kph":1.0,
"wind_gust_kph":"8.0",
"pressure_mb":"1018",
"pressure_in":"30.06",
"pressure_trend":"0",
"dewpoint_string":"59 F (15 C)",
"dewpoint_f":59,
"dewpoint_c":15,
"heat_index_string":"81 F (27 C)",
"heat_index_f":81,
"heat_index_c":27,
"windchill_string":"NA",
"windchill_f":"NA",
"windchill_c":"NA",
"feelslike_string":"81 F (27 C)",
"feelslike_f":"81",
"feelslike_c":"27",
"visibility_mi":"N/A",
"visibility_km":"N/A",
"solarradiation":"--",
"UV":"-1","precip_1hr_string":"-999.00 in ( 0 mm)",
"precip_1hr_in":"-999.00",
"precip_1hr_metric":" 0",
"precip_today_string":"0.00 in (0 mm)",
"precip_today_in":"0.00",
"precip_today_metric":"0",
"icon":"clear",
"icon_url":"http://icons.wxug.com/i/c/k/clear.gif",
"forecast_url":"http://www.wunderground.com/global/stations/07201.html",
"history_url":"http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=IPLONOUR3",
"ob_url":"http://www.wunderground.com/cgi-bin/findweather/getForecast?query=47.900333,-4.287129",
"nowcast":""
}
}
Les données qui m’intéressent sont :
- « current_observation » -> « display_location » -> « city »
- « current_observation » -> « temp_c »
- « current_observation » -> « relative_humidity »
- « current_observation » -> « wind_gust_kph »
- « current_observation » -> « forecast_url »
En PHP, j’ajoute le code suivant à mon fichier index.php :
<section class="capteurs">
<h3>wunderground</h3>
<?php
// http://stackoverflow.com/questions/20044579/how-to-get-a-value-from-wunderground-json
$json_string = file_get_contents("http://api.wunderground.com/api/APIkey/conditions/q/pws:IPLONOUR3.json");
$parsed_json = json_decode($json_string);
$location = $parsed_json->{'current_observation'}->{'display_location'}->{'city'};
$temp_c = $parsed_json->{'current_observation'}->{'temp_c'};
$humidity = $parsed_json->{'current_observation'}->{'relative_humidity'};
$wind_gust_km = $parsed_json->{'current_observation'}->{'wind_gust_kph'};
$forecast_url = $parsed_json->{'current_observation'}->{'forecast_url'};
echo "A ${location} : ${temp_c} °C, ${humidity} HR, rafales à ${wind_gust_km} km/h - <a target='_blank' href='${forecast_url}'>prévisions</a>. \n";
?>
</section>
Et maintenant mon tableau de bord affiche la température, l’humidité, la vitesse des rafales de vent et un lien vers les prévisions météo locales :

Et maintenant ?
Je vais maintenant intégrer une donnée issue de ma box domotique Eedomus. Ce sera l’objet du second article de cette série Un tableau de bord domotique.
par Anne-Laure DELPECH | 14 Août 2016 | Raspberry Pi
Les 5 précédents articles de cette série Caméra de surveillance et Raspberry Pi explorent différents aspects de la gestion de caméras de surveillance sur Rasberry Pi et la diffusion des flux vidéos sur une page web. Cet article en fait la synthèse.
L’objectif :
A partir d’une Raspberry Pi B+, installer motion réglé correctement pour :
- gérer deux caméras de surveillance IP ;
- collecter les vidéos et images générées sur détection de mouvement avec aussi peu de faux positifs que possible ;
- afficher les flux vidéos en temps réel sur une page web accessible sur le réseau local.
Préparation du Raspberry Pi
- Installer Raspbian Jessie Lite – voir l’article Mise en service d’un Raspberry Pi
- Régler le Pi pour fonctionner correctement en wifi sur une adresse fixe 192.168.1.104 (nom nautilus) – voir l’article Raspberry Pi : connexion internet en wifi et/ou IP fixe
Pour moi toutes ces étapes réalisées correspondent à l’image de carte sd « jessie-lite-wifi fixe-103-2016-07-16.img « , dans le répertoire « Downloads\2016-07 Pi Images « . Il me suffit de régler l’adresse wifi et le nom du Pi comme suit :
- Connecter le Pi en ethernet, sans dongle wifi ;
- Editer /etc/dhcpcd.conf et modifier l’adresse IP attribuée ;
- Taper raspi-config puis modifier Hostname (advanced options) et changer le nom vers « nautilus ».
- Mettre le dongle wifi sur le Pi puis taper « reboot » pour redémarrer.
Ensuite se reconnecter en wifi et mettre le Pi à jour :
- apt-get update
- apt-get upgrade
- rpi-update
Enlever la connexion ethernet et taper « reboot » pour redémarrer.
uname -a nous indique la version du système d’exploitation en fonctionnement.
Le résultat, le 14/08/2016 est 4.4.17+ #901 Fri Aug 12 17:48:40 BST 2016 armv6l GNU/Linux .
df -h montre qu’on utilise 17% de la carte SD de 8 Go.
Installer motion
apt-get install -y libjpeg62-turbo libjpeg62-turbo-dev libavformat-dev libavcodec-dev libavutil-dev libc6-dev zlib1g zlib1g-dev
apt-get install motion
Régler motion pour mes deux caméras
Il me faut 3 fichiers de configuration (droits d’accès 664, propriétaires motion / video) puisque j’ai deux caméras (cf l’article une caméra IP avec une vieille tablette android ?) :
- /etc/motion/motion.conf pour tous les éléments communs aux deux caméras ;
- /etc/motion/thread0.conf pour la caméra ‘Foscam’ ;
- /etc/motion/thread1.conf pour la caméra ‘galaxy’ ;
J’exécute donc les commandes suivantes pour créer les fichiers, et donner les bons droits :
chown -R root:root /etc/motion/
touch /etc/motion/thread1.conf
touch /etc/motion/thread0.conf
chown root:motion /etc/motion/thread0.conf
chown root:motion /etc/motion/thread1.conf
chmod -R 664 /etc/motion/
chmod 755 /etc/motion/
Nota : on trouve de nombreux tutoriels dans lesquels les droits de /etc/motion sont en 664 mais ça ne fonctionne pas dans mon cas.
Faire une copie de motion.conf au cas où :
cp /etc/motion/motion.conf /etc/motion/motion.conf.OLD
créer certains fichiers et donner les droits d’accès
Exécuter chaque ligne de commande non commentée :
# /usr/bin/motion : 755
chmod 755 /usr/bin/motion
#/var/lib/motion/ ne sert pas
#var/run/motion (pour motion.pid)
mkdir /var/run/motion
touch /var/run/motion/motion.pid
chown -R motion:motion /var/run/motion/
chmod 755 /var/run/motion/
chmod 644 /var/run/motion/motion.pid
# thread2.conf (foscam) : /home/jf/motion/log/foscam
# thread1.conf (tablette) : /home/jf/motion/log/galaxy
mkdir /home/jf/motion
mkdir /home/jf/motion/galaxy
mkdir /home/jf/motion/foscam
touch /home/jf/motion/motion-log.log
chown -R root:motion /home/jf/motion/
chown motion:motion /home/jf/motion/motion-log.log
chmod -R 644 /home/jf/motion/
chmod 777 /home/jf/motion/
chmod 775 /home/jf/motion/foscam/
chmod 775 /home/jf/motion/galaxy/
Attention, les fichiers créés avec touch via Cygwin sur mon PC sont en mode sauts de ligne Windows. Il faut les passer en saut de ligne UNIX (/home/jf/motion/log/motion-log.log et /var/run/motion/motion.pid).
éditer les fichiers de configuration
Dans etc/motion/motion.conf les lignes suivantes sont modifiées ou décommentées :
process_id_file /var/run/motion/motion.pid
logfile /home/jf/motion/log/motion-log.log
v4l2_palette 8
width 640
height 480
netcam_keepalive on
# Number of motion thread to show in SDL Window (default: 0 = disabled)
sdl_threadnr 0
text_double on
target_dir /home/jf/log/
# Restrict stream connections to localhost only (default: on)
stream_localhost off
webcontrol_port 8080 #must be in motion.conf, not in a thread.
# Restrict control connections to localhost only (default: on)
webcontrol_localhost off
# Output for http server, select off to choose raw text plain (default: on)
webcontrol_html_output on
thread /etc/motion/thread0.conf
thread /etc/motion/thread1.conf
Attention : il faut bien vérifier que thread0.conf et thread1.conf ont des sauts de ligne UNIX.
etc/thread0.conf règle la configuration pour la caméra devant la maison (évidemment il faut modifier USER et PWD ainsi que l’adresse IP pour que ça corresponde à la caméra) :
# caméra FOSCAM devant la maison
# thread0.conf
videodevice /dev/video0
netcam_url http://USER:PWD@192.168.X.X:80/videostream.cgi?user=USER&pwd=PWD
############################################################
# Régler sensibilité aux mouvements pour cette caméra extérieure
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/log/foscam
snapshot_filename f-%v-%Y%m%d%H%M%S-snapshot
picture_filename f-%v-%Y%m%d%H%M%S-%q
movie_filename f-%v-%Y%m%d%H%M%S
timelapse_filename f-%Y%m%d-timelapse
############################################################
stream_port 8081
etc/thread1.conf règle la configuration pour la caméra créée sur la vieille tablette samsung selon l’article une caméra IP avec une vieille tablette android ? :
#caméra Galaxy tab dans la maison
videodevice /dev/video1
netcam_url http://192.168.X.X: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/log/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
Démarrer motion comme un service
Dans /etc/default/motion, modifier la ligne suivante (passer à yes) :
start_motion_daemon=yes
Redémarrer le Pi avec reboot.
http://192.168.1.104:8082/ et http://192.168.1.104:8081/ affichent les deux flux vidéos sur un navigateur local.
Si ça ne fonctionne pas, modifier /etc/init.d/motion comme indiqué dans cet article, en y ajoutant la ligne sleep 30 . Pour moi, ça fonctionne sans.

Pour déboguer, on peut souhaiter savoir quel est l’utilisateur du service motion :
ps -aef | grep motion
Dans mon cas, ça montre deux utilisateurs (1ère colonne) : motion et root.

A ce stade, si on tape 192.168.1.104:8081 ou 192.168.1.104:8082 dans un navigateur du réseau local, on voit les flux vidéos en temps réel.
Supprimer les anciens fichiers image et vidéo
- créer le fichier camera–delete–cron.sh dans le répertoire /home/jf/motion et lui donner les droits d’acès 764
- Dans ce fichier, mettre les lignes suivantes :
#!/bin/bash
# /home/jf/motion/camera–delete–cron.sh
# 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 {} \;
- Dans le cron, via crontab -e, insérer les lignes suivantes :
#env
SHELL=/bin/bash
HOME=/home/jf
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* 1 * * * bash /home/jf/motion/camera-delete-cron.sh
- Redémarrer le Pi avec reboot.
Visualiser les flux vidéos sur une page PHP
- Installer apache et PHP – voir l’article Un serveur Web sur mon Raspberry Pi.
- dans le répertoire /var/www/html , créer une page index.php qui affiche les deux flux vidéos et y ajouter un fichier A-style.css .
- supprimer index.html
index.php contient :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Nautilus</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="A-style.css" rel="stylesheet" media="all" type="text/css">
</head>
<body class="pi-dashboard">
<H1>Tableau de bord maison 192.168.1.104 (nautilus)</h1>
<section class="video-surveillance">
<img name="Galaxy-Tab" class="stream" src="https://192.168.1.104:8082/?action=stream" width="600" height="450" alt="Live Feed" title="Galaxy Tab GT-P6210" />
<img name="Foscam-FI8905W" class="stream" src= "http://192.168.1.104:8081/?action=stream" width="600" height="450" title="Foscam FI8905W"/>
</section>
<section class="capteurs">
<h3>Autres informations</h3>
<p>A venir...</p>
</section>
</body>
</html>
A-style.css contient :
body {
padding: 0.3%;
font-family: Georgia, "Times New Roman",
Times, serif;
color: purple;
background-color: #d8da3d ;
width: 95%;
text-align: center;
}
section.video-surveillance {
display: flex; /* or inline-flex */
justify-content: space-around;
display: inline-block;
}
h1 {
font-family: Helvetica, Geneva, Arial,
SunSans-Regular, sans-serif ;
margin-top: 1em;
}
img.stream {
padding: 1%;
}
@media only screen and (min-width: 800px){
section.video-surveillance {
flex-direction: row ;
}
img.stream {
max-width: 45% ;
height: auto;
}
}
@media only screen and (max-width: 800px){
section.video-surveillance {
flex-direction: column ;
}
img.stream {
max-width: 95%;
height: auto;
}
}
A ce stade, la page php s’affiche lorsqu’on tape « nautilus » dans un navigateur local (192.168.1.104 dans une tablette)et les deux flux vidéos s’affichent en streaming.
df -h montre qu’on utilise maintenant 19% de la carte SD de 8 Go.
par Anne-Laure DELPECH | 20 Juil 2016 | bureautique, Cours en ligne
Je crée un cours (une formation) en ligne pour mon site professionnel. Je me rends compte que ce n’est pas si simple que ça de créer des vidéos à partir de powerpoint (2010) et d’un enregistrement de ma voix. J’ai déjà exposé les grands principes dans un article précédent (créer une vidéo à partir d’un Powerpoint (2010)). Ici je met en ligne mon mode opératoire précis. Ca servira au moins à m’en souvenir la prochaine fois !
Etape 1. Créer le Powerpoint.
Rien à dire de spécial là dessus.
Etape 2. Ecrire le texte qui sera ensuite dit
Je le met dans les commentaires, en caractères de taille 14.
Au fur et à mesure, je crée le résumé que je met sur la diapo et chaque fois que je résume une idée je passe à la ligne dans les commentaires.
(Cliquer sur l’image pour la voir en plus grand).
Etape 3. Préparer les changements de vue
Lorsque je dirai mon texte il faudra que je cliques sur le diaporama pour changer de page ou faire afficher les animations correspondants à ce que je dis.
Je crée donc les animations et j’indique « CLIC » dans le texte pour me souvenir que c’est à faire à ce stade.
(Cliquer sur l’image pour la voir en plus grand).
Etape 4. Créer l’aide visuelle pour dire le texte
J’imprime en pdf le diaporama en mode pages de commentaire.
C’est ce document qui me servira de script pour dire le texte.
(Cliquer sur l’image pour la voir en plus grand).
Etape 5. s’entraîner et vérifier
J’ai connecté un deuxième écran à mon PC. Je pourrais aussi utiliser un vidéoprojecteur en le réglant pour qu’il ne duplique pas l’écran de l’ordinateur.
J’ouvre le pdf du texte à dire dans le deuxième écran.
Je démarre le diaporama dans le premier écran.
Je dis le texte une ou deux fois pour vérifier que les clics vont bien, que mon texte va bien. Si nécessaire je modifie le diaporama et je crée un nouveau pdf du texte à dire.
Etape 6. Dire le texte dans le powerpoint
J’utilise un micro Yeti (ici sur amazon). Il est cher mais permet de régler la direction du son. C’est très utile dans certaines circonstances. Je le connecte en USB à mon ordinateur et je vérifie que le bouton mute est désactivé (la LED rouge est fixe lorsqu’il peut enregistrer, clignotante lorsqu’il est sourd / mute).
Nota : la façon de faire un enregistrement sonore et minuter les animations est décrite dans le premier article sur les vidéos à partir d’un Powerpoint.
Je fais un premier test vite fait pour m’assurer que le micro est bien réglé :
- j’enregistre quelques phrases puis j’arrête l’enregistrement ;
- Je lis la diapo en mode diaporama. Si le son est bon, j’efface l’enregistrement et je procède maintenant à la version définitive.
- je commence à la première diapo, en enregistrant à la fois le son et le minutage.
- Lorsque j’ai fini la première diapo, j’arrête l’enregistrement.
- Je me place sur la deuxième diapo et je choisis « démarrer l’enregistrement à partir de la diapositive actuelle ».
- Et ainsi de suite jusqu’à la fin du diaporama. Evidemment, il est prudent de faire des sauvegardes intermédiaires.
Etape 7 : vérifier puis transformer en vidéo
J’enregistre en qualité ‘Qualité HD & ordinateur’ puisque je vais ensuite la mettre en ligne via Viméo qui gérera la qualité en fonction de la bande passante de l’internaute.
J’obtiens un fichier WMV d’environ 8 Mo pour 58 » de vidéo (en qualité internet et DVD, la même vidéo ferait 3 Mo.
Etape 8 : mettre la vidéo en ligne (sur VIMEO)
J’ai acheté un compte « plus » sur Vimeo, qui permet de gérer la confidentialité des vidéos mises en ligne. C’est très simple.
On peut mettre en ligne soit en faisant glisser le fichier dans la zone correspondante, soit, encore mieux, via dropbox (c’est beaucoup plus rapide puisque je ne monte qu’une seule fois le fichier sur internet).
Etape 9 : régler les paramètres de la vidéo (sur VIMEO)
Paramètres basic :
Paramètres Confidentialité :
- Qui peut regarder cette vidéo : masquer cette vidéo sur vimeo.com (Cette vidéo peut être intégrée à d’autres sites mais ne peut pas être visionnée sur Vimeo.com)
- Où est-ce que cette vidéo peut être intégrée ? : seulement sur les sites de mon choix (et saisir les noms de domaine)
- Qui peut commenter cette vidéo : tout le monde
- Que peuvent faire les gens avec cette vidéo : ne rien cocher (pas de téléchargement, pas d’ajout à une collection)
Paramètres collections
- Album : cocher le bon album
Paramètres Intégration
- Pré-réglage « cours – par défaut »

Paramètres Avancé :
- Licence Creative Commons : aucune
Intégrer la vidéo sur une page WordPress
Le domaine d’intégration doit avoir été défini dans les paramètres de confidentialité.
Dans Viméo, cliquer sur « share » en haut à droite de la vidéo. Copier le lien et le coller directement dans l’éditeur visuel du contenu WordPress de destination
Et voilà, c’est fait !
Commentaires récents