Génération de PDF avec CodeIgniter

Introduction

Dans votre application, vous désirez générer un fichier PDF avec vos données, votre charte graphique, etc. Voici un exemple d’utilisation d’une bibliothèque, qui permet de faire :

  • une entête
  • un pied de page
  • ajouter une pagination (numéro de la page en cours ; nombre de page du document)
  • insérer des images
  • insérer du texte HTML

 http://hulan.info/item/html2pdf-convert-your-xhtml-to-pdf-easily

 

Démarrage

Voici comment procéder pour installer cette bibliothèque dans votre projet :

  • Copier dans application/libraries les fichiers :
    • Fpdf_rotate.php
    • Fpdf.php
    • Pdf_html.php
    • Pdf.php
  • Copier dans application/third_party les fichiers :
    • tout le répertoire « fpdf/fonts »
  • Modifier le fichier application/config/config.php avec ces lignes :
//FPDF FONT DIRECTORY
$config['fonts_path'] = APPPATH.'third_party/fpdf/fonts/';

 

 

Générer le PDF depuis votre controller

Définir le point d’entrée du controller (classique CodeIgniter), par exemple « getAttestation() » :

public function getAttestation(){

 

Définir le répertoire des polices :

define('FPDF_FONTPATH',$this->config->item('fonts_path'));

 

Charger les bibliothèques :

$this->load->library(array('fpdf','fpdf_rotate','pdf', 'pdf_html'));

 

Mettre du contenu dans le PDF :

$pdf = new PDF_HTML();

$pdf->Open();
$pdf->SetTopMargin(10);
$pdf->AliasNbPages();
$pdf->AddPage();
$pdf->SetFont('Arial', '', 12);
$pdf->SetDrawColor(0);

$pdf->SetTitle('Attestation');
$pdf->Ln(5);
$pdf->SetFontSize(16);
$pdf->x = 70;
$pdf->Write(0, utf8_decode( "OK") );
$pdf->Output('', 'I'); // I : inline file

 

et terminer la fonction « getAttestation() »:

}

Lorsqu’on lance l’URL de ce controller dans le navigateur, un fichier PDF est généré :

 

Le fichier a pour titre « Attestation », comme prévu par le code.

Codeigniter 3 chez free.fr

Codeigniter 3

J’utilise le framework Codeigniter pour mes projets personnels, avec mon générateur de code. Sa simplicité d’utilisation et sa rapidité de mise en œuvre restent un atout majeur pour de petites applications web.

En voulant faire une requête de groupe, comme ceci, je me suis confronté à un problème :

select a, b from table1, table2
where table1.c1 = table2.c1
and c1 > 10
or (c2 > 20 and c3 > 30);

 

Les opérations avec les parenthèses sont réalisables de 2 façons :

  1. Faire la requête en SQL pure et la lancer dans CodeIgniter. C’est assez moche et doit être réservé à des requêtes complexes, visant à faire travailler le moteur du SGBD. La requête sera travaillée dans un MySQL Workbench pour être sûr du résultat. On restera alors sur une base de donnée d’un certain type (ex : MySQL), sans pouvoir passer un jour à un autre type (ex: SQLite).
  2. Passer à CodeIgniter 3 pour utiliser la fonctionnalité de regroupements dans les requêtes : voir la documentation dans CodeIgniter

Cette seconde méthode exploite pleinement le SQLBD tout en utilisant le QueryBuilder du Framework. Sauf que pour ça, il faut passer à CodeIgniter 3.

 

Et free dans tout ça ?

L’hébergeur free.fr est gratuit, oui. Mais il est aussi :

  • lent au chargement
  • limité dans l’accès FTP sur le nombre de sessions ouvertes, ce qui est assez pénalisant à l’usage
  • limité dans les bases de données par site (1 seule)
  • ancien, dans les techno qu’il nous mets à disposition
  • permissif, non sécurisé (piratage de compte vécu)
  • sans support (newsgroup étant le seul media d’échange, il reste sans réponse)

Pour que CodeIgniter 3 fonctionne, il doit utiliser PHP 5.2 minimum. Or, chez free, il est à la version 5.1 – dommage !

Pour ces multiples raisons, j’ai ouvert un autre site chez WebHost et j’ai fait un test chez eux.

 

Résultats

A part l’interface de gestion assez « old-scool », on retrouve ses repères. Ouverture de site, ouverture de compte mail, création de base de données MySQL, accès FTP : tout ça se fait très facilement et rapidement.

Mon choix est fait, adieu free, enfin pas pour tout. Je garde mon blog, même si je me sens dans une toute petite boite, sans pouvoir étendre mes jambes ou mes bras (version de WordPress assez ancienne, ne pouvant pas se mettre à jour, pas d’accès aux serveurs externes pour mettre un captcha, etc…).

 

Arduino + ESP8266 : connexion Wifi

Introduction

La carte Arduino peut être connectée à un module de connexion Wifi (nommé ESP8266) pour lequel une configuration est nécessaire.

Voici la façon dont j’ai pu envoyer un simple HTTP GET depuis la carte Arduino avec ce module.

Dans certains tutoriels qu’on peut trouver sur le Net, il est mentionné la mise à jour du firmware, par l’intermédiaire d’une autre carte électronique. Cet article part du module sorti de son emballage, sans faire cette mise à jour.

 

Le module ESP8266

Ce module est un regroupement de multiples composants, sous forme de mini-carte électronique, avec 8 broches de connexion.
Il mesure 2.5 cm x 1.5 cm et coûte 7.33 € sur Amazon.

Il permet de se connecter à un point d’accès Wifi pour communiquer en mode client/serveur (être client ou être serveur) mais il peut aussi être défini en tant que point d’accès Wifi.

Branchements

Il faut brancher le composant avec la carte Arduino, de manière précise, sur le 3.3v.

 

Détail des branchements :

L’article http://www.labradoc.com/i/follower/p/notes-esp8266 détaille les branchements. En voici un rappel (en Français) :

  • RX vers le port TX de la carte Arduino
  • VCC vers le port 3.3v de la carte Arduino
  • GPIO 0 non branché
  • RESET non branché
  • CH_PD vers le port 3.3v de la carte Arduino
  • GPIO 2 non branché
  • TX vers le port RX de la carte Arduino
  • GND vers le port GND de la carte Arduino

Si vous avez branché RX et TX correctement, une LED bleue sur le module ESP8266 émet un bref flash lors de la mise sous tension. Si elle ne s’allume pas, c’est que le branchement n’est peut-être pas bon…

Quelques conseils :

  • Branchez tout et à la fin, le fil qui va vers 3.3v. Vous saurez si tout est opérationnel ou non avec cette LED bleue.
  • Il ne faut rien brancher avec le port 5v de la carte Arduino. En cas d’erreur, le module grillera. Je vous conseille donc de brancher un fil sur ce port 5v et de laisser non branché à l’autre bout du fil (par exemple, faire un nœud pas trop serré).

 

Comment donner des ordres au module ESP8266 ?

L’article http://www.labradoc.com/i/follower/p/notes-esp8266 détaille les commandes à passer par l’interface de programmation d’Arduino. Pour résumé, une série de commandes doivent être passées pour :

  • Initialiser le module ESP8266
  • Se mettre en mode client Wifi (et pas en mode point d’accès)
  • (en option) Rechercher les points d’accès disponibles (et afficher leur SSID)
  • (en option) Se définir une adresse IP
  • Se connecter sur un point d’accès (avec SSID et mot de passe)
  • Se mettre en mode « Connexions multiples » (pour faire plusieurs appels HTTP)
  • (en option) Afficher son adresse IP
  • (en option) Faire un PING sur un serveur
  • Faire un HTTP GET
  • Fermer la connexion (et préparer le prochain appel HTTP)

Ces commandes sont à transmettre par le port Série de la carte Arduino.

 

Code pour faire les appels HTTP GET

Avec Adruino, 2 fonctions sont préparées pour que l’utilisateur écrive son code à l’intérieur, avec 2 objectifs :

  • setup() : cette fonction est lancée une seule fois au démarrage de la carte Arduino
  • loop() : après la fonction « setup() », cette fonction est lancée autant de fois que la carte Arduino est allumée

Une partie d’initialisation est faire avant ces 2 fonctions

#include <SoftwareSerial.h>

String ssid = "NETGEAR";
String key = "pA$$W0Rd";

SoftwareSerial esp8266(1, 0); // RX, TX
bool done = false;

Seule la bibliothèque SoftwareSerial est nécessaire.

La variable « done » sera utilisée de manière globale.

 

Code de la fonction setup()

 void setup() {
  // put your setup code here, to run once:

  esp8266.begin(115200);
  delay(500);
  esp8266.println("AT+RST");

  /**
   * Initialisation
   */
  delay(1000);
  esp8266.println("AT");
  done = esp8266.find("OK");
  if(!done){
    delay(1000);
    done = esp8266.find("OK");
  }

  /**
   * Se mettre en mode CLIENT
   */
  esp8266.println("AT+CWMODE=1");
  done = esp8266.find("OK");
  if(!done){
    delay(1000);
    done = esp8266.find("OK");
  }

  /**
   * Affecter son adresse IP manuellement
   */
   /*
  delay(1000);
  esp8266.println("AT+CIPSTA=\"192.168.1.200\",\"192.168.92.254\",\"255.255.255.0\"");
  done = esp8266.find("OK");
  while(!done){
    delay(1000);
    done = esp8266.find("OK");
  }*/

  /**
   * Rechercher les points d'accès WIFI
   */
   /*
  delay(1000);
  esp8266.println("AT+CWLAP");
  done = esp8266.find("OK");
  while(!done){
    delay(1000);
    done = esp8266.find("OK");
    delay(3000);
    break;
  }*/

  /**
   * Se connecter au point d'accès Wifi défini dans la variable "ssid"
   */
  esp8266.println("AT+CWJAP=\""+ssid+"\",\""+key+"\"");
  done = esp8266.find("OK");
  while(!done){
    delay(1000);
    done = esp8266.find("OK");
  }

  /**
   * Se mettre en mode connexions multiples
   */
  esp8266.println("AT+CIPMUX=1");
  done = esp8266.find("OK");
  if(!done){
    delay(1000);
    done = esp8266.find("OK");
  }

  /**
   * afficher son adresse IP
   */
  esp8266.println("AT+CIFSR");
  done = esp8266.find("STAIP");
  if(!done){
    delay(1000);
    done = esp8266.find("OK");
  }

  /**
   * faire un ping sur un server
   */
   /*
  delay(1000);
  esp8266.println("AT+PING=\"192.168.1.100\"");
  done = false;
  if(!done){
    delay(1000);
    done = esp8266.find("OK");
  }*/

}

Il est nécessaire de mettre des temps d’attente (moins une seconde maxi) pour que le module se mette dans un état convenable, qu’il communique avec le point d’accès Wifi. Sinon, vous aurez des messages du genre « busy p… » ou « busy s… », qui peuvent être bloquant ou non.

Ajustez ces temps selon vos résultats.

 

Code de la fonction loop()

void loop() {
  int maxLoops = 5;

  /**
   * Faire un HTTP GET
   */
  String cmd = "AT+CIPSTART=4,\"TCP\",\"192.168.1.100\",80";
  esp8266.println(cmd);
  delay(500);
  done = esp8266.find("OK");
  int currentLoop = 0;
  while(!done){
    delay(500);
    done = esp8266.find("OK");
    if(currentLoop >= maxLoops){
      break;
    }
    currentLoop++;
  }

  String url = "/lda/index.php/data/createdatajson/append?datflval=1.55&thing=FIRST";
  String cmdGET = "GET " + url + " HTTP/1.1\r\n"+
    "Host: 192.168.1.100\r\nUser-Agent: ESP8266_HTTP_Client\r\nConnection: close\r\n\r\n";
  esp8266.print("AT+CIPSEND=4,");
  esp8266.println(cmdGET.length());
  delay(1000);
  done = esp8266.find(">");
  currentLoop = 0;
  while(!done){
    delay(500);
    done = esp8266.find(">");
    if(currentLoop >= maxLoops){
      break;
    }
    currentLoop++;
  }
  esp8266.println(cmdGET+"\r\n\r\n");
  delay(1000);

  esp8266.println("AT+CIPSTATUS");
  delay(1000);

  // Close all connections
  esp8266.println("AT+CIPCLOSE=5");
  delay(1000);

  // restart from zero
  esp8266.println("AT");

  // 4 secondes déjà passées
  delay(20000);

}

 

Je désire faire l’appel à l’URL « http://192.168.1.100:80/lda/index.php/data/createdatajson/append?datflval=1.55&thing=FIRST » en GET. Tous les paramètres de cette requête sont après le caractère « ? ».

J’ai un serveur HTTP qui est capable de lire cette requête et de stocker la valeur « 1.55″ pour un objet « FIRST » dans une base de données.

Ce code se découpe en plusieurs parties :

  1. Se connecter au serveur 192.168.1.100, en mode TCP, sur le port 80 : « AT+CIPSTART=… ». Il faut attendre que le moduleESP8266 réponde « OK » pour continuer.
  2. Appeler l’URL en GET : « AT+CIPSEND=… ». Il faut absolument ajouter dans l’entête de cette requête le « Host: xxx », sinon le serveur répond « Error HTTP 400 : BAD REQUEST ». Pour être propre, je rajoute « User-Agent » et « Connection ». Les « \r\n » sont importants. A la fin, il faut les mettre en double : « \r\n\r\n ». Sinon, le serveur attend des données.
  3. (En option) Demander le statut de la connexion : « AT+CIPSTATUS ». elle doit être fermée (le serveur a pris la requête est il a fermé la connexion)
  4. S’assurer que toutes les connexions sont bien fermées : « AT+CIPCLOSE=5″ (le chiffre 5 signifie ‘toutes les connexions’)
  5. Réinitialiser le module ESP8266 : « AT ». Lors de la prochaine connexion au serveur (étape 1 de la boucle), la connexion Wifi sera conservée.
  6. Attendre 20 secondes pour le prochain envoi de données

Ici aussi, les délais d’attente entre les commandes sont importants. Ils peuvent être personnalisés selon votre besoin, mais ils ne pourront pas être mis à 0.

 

Envoi vers la carte Arduino

Les ports TX et RX sont utilisés lors du transfert du programme vers la carte Arduino. si vous laisser le 3.3v branché, Il faudra débrancher les TX et RX pour que le transfert se fasse correctement. Je réitère donc mon conseil de débrancher le 3.3v lors du transfert.

 

Résultat sur le serveur

Les données sont toutes récupérées, à intervalle régulier (toutes les 24 secondes) :

 

Trace laissée par le module

Dans la console « Moniteur série », voici les infos affichées par le module. On y trouve les commandes passées et les réponses du module.

Ai-Thinker Technology Co.,Ltd.

ready
AT

OK
AT+CWMODE=1

OK
AT+CWJAP="NETGEAR","pA$$W0Rd"

WIFI CONNECTED
WIFI GOT IP

OK
AT+CIPMUX=1

OK
AT+CIFSR

+CIFSR:STAIP,"192.168.1.200"
+CIFSR:STAMAC,"5c:cf:7f:10:d6:ab"

OK
AT+CIPSTART=4,"TCP","192.168.1.100",80

4,CONNECT

OK
AT+CIPSEND=4,157

OK
> 

busy s...

Recv 157 bytes

SEND OK

+IPD,4,728:HTTP/1.1 200 OK
Date: Sat, 16 Jan 2016 17:32:03 GMT
Server: Apache/2.4.12 (Ubuntu)
Set-Cookie: ci_session=a%3A5%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%227c75547487eb7803fa0afe75dead178d%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A13%3A%22192.168.1.200%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A19%3A%22ESP8266_HTTP_Client%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1452965523%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7Deb938672b48c15066e92aef755ab6250; expires=Sat, 16-Jan-2016 19:32:03 GMT; Max-Age=7200; path=/
Access-Control-Allow-Origin: *
Vary: Accept-Encoding
Content-Length: 81
Connection: close
Content-Type: text/html; charset=UTF-8

{"datiddat":41,"datflval":"1.55","datdhacq":"2016-01-16 18:32:03","datidthn":"1"}4,CLOSED
AT+CIPSTATUS

STATUS:4

OK
AT+CIPCLOSE=5

OK
AT

OK
AT+CIPSTART=4,"TCP","192.168.1.100",80

4,CONNECT

OK
AT+CIPSEND=4,157

OK
> 

busy s...

Recv 157 bytes

SEND OK

+IPD,4,728:HTTP/1.1 200 OK
Date: Sat, 16 Jan 2016 17:32:27 GMT
Server: Apache/2.4.12 (Ubuntu)
Set-Cookie: ci_session=a%3A5%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%220a10f1ca33ba3316e6acfee18ba76b2f%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A13%3A%22192.168.1.200%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A19%3A%22ESP8266_HTTP_Client%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1452965547%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7Db946991f8b9d1ef88d0667330b515767; expires=Sat, 16-Jan-2016 19:32:27 GMT; Max-Age=7200; path=/
Access-Control-Allow-Origin: *
Vary: Accept-Encoding
Content-Length: 81
Connection: close
Content-Type: text/html; charset=UTF-8

{"datiddat":42,"datflval":"1.55","datdhacq":"2016-01-16 18:32:27","datidthn":"1"}4,CLOSED
AT+CIPSTATUS

STATUS:4

OK
AT+CIPCLOSE=5

OK
AT

OK
...

 

Annexe

Toutes les commandes et la doc technique (en anglais) de ce module ESP8266 : https://nurdspace.nl/ESP8266

Code complet : téléchargez

 

Raspberry : un feu de cheminée ou un aquarium

Introduction

Noël approche, qui n’a pas rêvé d’avoir un feu de cheminée. Je vous propose de transformer votre Raspberry en « boite à diffuser une vidéo de distraction », comme un feu de cheminée, un aquarium ou une jolie vue de ruisseau.

 

Configuration du Raspberry

Rien de plus qu’un Raspberry qui fonctionne et qui est connecté à un écran.

 

Choix de la vidéo

Youtube fourni un grand nombre de vidéos, en HD de feu de cheminée ou d’aquarium. Voici mon choix :

https://www.youtube.com/watch?v=0fYL_qiDYf0

La vidéo dure 2 heures, mais on n’a besoin de tout le fichier. Il faut passer par une outil de téléchargement (cherchez « youtube downloader firefox plugin ») pour récupérer le fichier MP4.

 

Extraction d’une portion de quelques minutes

Passez par ffmpeg pour extraire une partie de la vidéo. Notez la période : début et durée, puis lancer la ligne de commande suivante pour l’extraction :

ffmpeg -ss 00:30:00 -i feuDeCheminee-full.mp4 -t 00:02:00 -vcodec copy -acodec copy feu-portion.mp4

Sur la vidéo « feuDeCheminee-full.mp4 », je saute 30 minutes du début et je prends 2 minutes de vidéo finale. Le fichier « feu-portion.mp4 » contiendra le résultat : une vidéo de quelques dizaines de Mo (au lieu de plus d’un Go pour la vidéo complète).

 

Lire la vidéo avec le Raspberry

Tentez de lire la vidéo avec VLC : c’est très lent. Impossible de choisir cette solution. En allant voir sur le Net, le player conseillé est « omxplayer ». Cherchez à l’installer avec les bibliothèques pour être sûr du résultat.

Mon Raspberry est configuré en point d’accès Wifi, avec une application Web pour le piloter (depuis mon smartphone ou depuis un PC). J’ajoute cette fonctionnalité, en appelant un script pour lancer la vidéo :

#!/bin/bash

export DISPLAY=:0.0

SERVICE='omxplayer'
RES=0
trap "exit" INT
while [ $RES -eq 0 ]; do
  if ps ax | grep -v grep | grep $SERVICE > /dev/null
  then
    sleep 1
  else
    xterm -fullscreen -fg black -bg black -e omxplayer --win "0 0 1600 1200" -r $1
    RES=$?
    echo "RES: $RES"
  fi
done

xrefresh -display :0

 

Vous constaterez des lignes particulières (que j’utilise peu) :

trap "exit" INT

Cela signifie que si un sous-script est lancé et qu’il se fait killer, le script s’arrête aussi.

 

xrefresh -display :0

A la fin du script, je force le rafraîchissement de l’écran pour nettoyer ce qui peut rester.

 

xterm -fullscreen -fg black -bg black -e omxplayer --win "0 0 1600 1200" -r $1
RES=$?

La ligne de commande principale, qui lance la vidéo, dans un terminal (xterm), en plein écran, avec omxplayer en mode fenêtre, d’une taille de 1600×1200. La variable RES récupère le code retour du player. Si elle vaut 0, on boucle, sinon, on s’arrête (le CTRL-C fait un RES = 2).

Pour simuler la lecture sans fin, j’ai une boucle while autour de tout ça.

 

Arrêt de la lecture par un script

J’ai aussi un autre script qui arrête la lecture en boucle :

PID=$(ps aux | grep omxplayer | awk {'print $2'})
kill -9 $PID 2>/dev/null

xrefresh -display :0

Rien de très novateur. J’ai essayé la commande « killall -9 omxplayer », mais elle n’est pas satisfaisante.

Mon interface (depuis un PC) pour lancer quelques vidéos et un bouton en bas pour arrêter :

OpenCV pour mesurer la qualité des images – update

Introduction

Un premier article (OpenCV pour mesurer la qualité des images) a été rédigé il y a fort longtemps sur la mesure de qualité d’une image ou d’une photo, par rapport au flou ou au défaut de mise au point. A vrai dire, je n’étais pas complètement satisfait du résultat, en comparant 2 photos ayant de légères différences de netteté. Après d’autres recherches et tests, voici une version nettement améliorée.

 

Le script v2

import cv2, sys

filepath = sys.argv[1]
filename = sys.argv[2]

myCamera = cv2.VideoCapture(0)
if myCamera.isOpened():
    ret, frame = myCamera.read()
    gray = cv2.cvtColor( frame, cv2.COLOR_BGR2GRAY)
    variation = cv2.Laplacian(gray, cv2.CV_64F).var()

    finalFilename = "%s/%d-%s" % (filepath, variation, filename)
    cv2.imwrite(finalFilename, frame)

 

Notes et remarques

Ce script donne un autre résultat, en se basant sur une image en tons de gris et en calculant le laplacien. Ensuite, il calcule la variation sous forme d’un scalaire, donc facilement exploitable pour trier les photos nettes de celles qui le sont moins.

Ce script est utilisé pour un mode « rafale » de prises de vues sur une webcam (derrière un télescope), pour isoler les photos les plus nettes. L’indice de qualité est le préfixe du nom de fichier, donc c’est facile d’avoir les 50 meilleures photos et les 50 les plus floues.

 

Raspberry Pi + Camera : pilotage par un smartphone

Intérêt

Le raspberry est une petite boite contenant l’équivalent d’un PC assez puissant pour faire quelques petites choses intéressantes. L’objectif est de brancher le raspberry sur une source d’alimentation (dans la voiture, près de la télé, sous un télescope) et de piloter quelques actions depuis un smartphone.

Exemples d’application :

  • Près d’un point de surveillance de la maison : Caméra de surveillance, avec enregistrement des vidéos sur une clé USB
  • Dans la voiture : Enregistrement de la conduite de manière automatique. en cas de litiges, vous aurez un enregistrement vidéo
  • Sous un télescope : avec une webcam derrière l’objectif pour faire la mise au point et une série de prises de vue enregistrées sur la clé USB
  • Près d’un moniteur ou d’une télé : pour lancer une présentation PowerPoint / PDF, pour jouer des vidéos, avec la webcam pour prendre des photos

Tout ça, avec un smartphone en guise de télécommande Wifi.

 

Configuration matérielle pour le démarrage

Voici le matériel nécessaire pour configurer le Raspberry complètement :

  • Un clavier USB
  • Une souris USB
  • Un écran
  • Une clé USB
  • Un accès à Internet

 

Configuration logicielle pour le démarrage

  1. Installation de l’image Ubuntu Mate pour Raspberry
  2. Installation des services :
    1. LAMP (Apache + PHP + MySQL), avec changement du user apache
    2. openssh-server (pour accès shell par SSH)
    3. usbmount (auto-mount les clés USB)
  3. Configuration des points de montage : pour la clé USB :  « uid=1000,noauto,user »
  4. Désactivation du firewall Ubuntu
  5. Installation d’un serveur FTP et SSH pour déposer les fichiers depuis un autre PC et lancer des lignes de commandes

 

Configuration logicielle étape 2

Cette étape se fait depuis un PC pour plus de confort. On a donc mis le Raspberry sur un réseau interne :

  • Un PC connecté via RJ45 à un routeur
  • Le Raspberry connecté en RJ45 au routeur

Par la suite, le câble RJ45 sera supprimé.

 

Le clavier, la souris et l’écran peuvent être supprimés après avoir installé les serveurs SSH et FTP.

L’installation d »es logiciels continue :

  1. Installation d’une application web pour accéder au Raspberry depuis un smartphone (PHP avec CodeIgniter) – Réalisée par mes soins ; cf chapitre « Application web pour contrôler le Raspberry » ci-dessous
  2. Changement de la politique de sécurité pour autoriser l’arret et reboot par un utilisateur quelconque (/usr/share/polkit-1/actions/org.freedesktop.login1.policy)
  3. Connexion automatique d’un user (pour ne pas avoir de mire de connexion)
  4. Ajout d’un script à la connexion pour lancer « xhost + » (pour que d’autres machines puissent ouvrir des fenêtres dans la session ouverte)
  5. Activation du dongle Wifi en mode AccessPoint (point d’accès Wifi) et paramétrage du DHCP

 

Application web pour contrôler le Raspberry

Cette application web permettra de piloter le Rasbberry depuis un smartphone. Elle est développée en PHP avec le Framework CodeIgniter. Un template HTML permet d’avoir une charte graphique en Responsive Design : http://binarycart.com/bclivedemos/01-05-2014/v1/bs-binary-admin/index.html

 

Fonctionnalités basiques de l’application PHP :

  • Etat du raspberry : charge machine, type de processeur, version du noyau, version et nom du système (Ubuntu)
  • Lancement de scripts SH (exemple : lancer une présentation avec un fichier PDF précis)
  • Parcours dans les répertoires
  • Caméra : prise de photo, enregistrement d’une vidéo
  • Arrêt et relance du raspberry

 

Utilisation avec un smartphone

Après avoir mis sous tension le raspberry, le smartphone peut s’y connecter par wifi. Un simple navigateur permet d’accéder aux fonctionnalités. Le smartphone devient une télécommande.

 

Copies d’écran sur smartphone

Page de connexion

Page d’accueil : description de la machine

Menu

Page des scripts à lancer

Page des médias USB connectés et détectés

Parcours des fichiers du Raspberry

Page de la gestion de la caméra : prendre une photo, prendre des vidéos

Page d’arrêt / relance du Raspberry

Réclame : Protection écran de smartphone

Après avoir prêté mon smartphone aux collègues, j’ai du enlever 5ml d’huile de coude sur la vitre pour m’en servir. La surface s’est comporté comme une véritable éponge à saleté.

J’ai alors testé une protection vendue par docphone.org pendant mes vacances d’été. Même la crème solaire et le sable n’y sont pas venus à bout. Expérience concluante. J’attends mes collègues pour l’ultime test « prends un autre croissant et va taxer le Samsung de Julien ».

GanttCalendar + VectorManager

Utilisation de VectorManager

VectorManager est une bibliothèque JS destinée à gérer les vecteurs au sens mathématique (développée par l’auteur de cet article). Avec le GanttCalendar, il est possible de faire calculer à cette bibliothèque JS une information sur l’occupation des ressources d’un calendrier. Le GanttCalendar a donc été mis à jour avec VectorManager pour ajouter cette information pertinente : « au moins une ressource est occupée » et « toutes les ressources sont occupées ».

Pour ces 2 informations, 2 barres sont ajoutées dans le groupe de ressources :

  • bleu : « au moins une ressource est occupée »
  • rouge : « toutes les ressources sont occupées »

 

Bonus : Cette représentation supporte le zoom sur les calendriers sans ajouter de code spécifique. C’est l’avantage de rester sur la notion mathématique le plus loin possible dans le code, jusqu’au moment de l’affichage.

 

Exemples

Calendrier hebdomadaire :

Zoom sur le calendrier mensuel :

 

Démo

Les liens suivants permettent de voir le résultat en live :

Ces pages ont été testées avec FireFox. Il est fort probable qu’Internet Explorer n’affiche pas correctement les calendriers.

 

Sources

https://github.com/jchome/ganttCalendar

OpenCV pour mesurer la qualité des images

Introduction

J’ai passé une autre soirée astro pour prendre des photos de Jupiter. Environ 220 clichés de plus ou moins bonne qualité, en fonction de l’atmosphère sont à trier. En général, certaines photos sont trop floues.

Comment faire le tri entre toutes ces photos pour ne garder que les plus nettes ? OpenCV va vous sauver la vie !

 

Principe

L’objectif est d’avoir un chiffre « qualité du focus », calculé sur chaque photo qui me permettra de trier mes 220 photos pour n’en sortir que les 100 plus nettes.

Pour ce faire, la technique la plus en vogue sur le net (stack overflow + publications) et de faire 2 filtres Sobel sur l’image, calculer les pics de gradients et faire une somme globale. Plus la somme est élevée, plus il y a de netteté.

 

Rappel / info à savoir

Sobel est un des filtres de détection des bords les plus connus (expliqué à la fac, dans des TP, etc). On peut citer aussi le Laplacien dans cette famille de filtres. Depuis une image en couleurs, ces filtres vont faire une image en dégradé de gris, avec :

  • en noir : les régions où il n’y a pas de bord (aplat de couleur ou changement doux)
  • en blanc : changement brutal de couleur (= un bord)

Ce qui est pratique avec Sobel, c’est qu’on peut lui dire dans quel axe il doit détecter les bords. Pour nous, ce sera un dans l’axe X et un dans l’axe Y de chaque image. Les pics de gradients se feront sur ces 2 axes pour avoir une large gamme de détection.

 

OpenCV

Ce n’est pas le premier script Python posté sur mon site qui utilise OpenCV. Pour ceux qui ne le savaient pas, Python a été créé à l’époque (au siècle dernier) pour interfacer du C/C++, donc faire des appels de fonctions programmées en C et compilées sur le PC. Ceci avec un langage plus simple que le C : le Python !

Bref, OpenCV propose une tonne de fonctions pour manipuler les images. Toutes, très éprouvées, très optimisées, et très math… (désolé pour les non-matheux)

 

Le script

Voici le script Python qui prend en entrée une liste d’images et sort un tri par netteté.

#!/usr/bin/python

import cv2, sys
import operator

files = sys.argv[1:]
all_ratio = {}
for filename in files:
    orig = cv2.imread(filename)

    sobel_dx = cv2.Sobel(orig, cv2.CV_64F, 1, 0, ksize=5)
    sobel_dy = cv2.Sobel(orig, cv2.CV_64F, 0, 1, ksize=5)
    magnitude_image = cv2.magnitude(sobel_dx,sobel_dy,sobel_dx);
    mag, ang = cv2.cartToPolar(sobel_dx, sobel_dy, magnitude_image) 

    ratio = cv2.sumElems(mag[0])
    all_ratio[filename] = ratio[0]

sorted_ratio = sorted(all_ratio.items(), key=operator.itemgetter(1))
index = 1
print(" Rang | Fichier      | Valeur calculee")
print("------|--------------|----------------")
for (filename, ratio) in reversed(sorted_ratio):
    print(" %04d | %s | %d" % (index, filename, ratio))
    index += 1

 

Exemple

Voici les 3 images utilisées dans l’appel du script (cliquez pour voir la photo originale) :

  • Image « apero girl.png », originale :
  • image « apero girl-5.png », copie de l’image originale, avec un flou gaussien de 5px :
  • image « apero girl-20.png », copie de l’image originale, avec un flou gaussien de 20px :

Résultat du script :

 Rang | Fichier      | Valeur calculee
------|--------------|----------------
 0001 | apero girl.png | 154324
 0002 | apero girl-5.png | 146422
 0003 | apero girl-20.png | 142630

Conclusion : l’image « apero girl.png » est le plus net.

 

Remarque

En regardant le script « dans le blanc des yeux », on serait tenté de dire ceci : oui, mais ton script ne te donne de bons résultats uniquement sur des photos proches, d’une prise de vue d’un même objet, qui serait plus ou moins flou.

Et bien, en effet, si on prend 2 photos qui n’ont rien à voir, les indices calculés seront incohérents et le tri par « qualité de netteté » ne voudra rien dire.

Donc, restez vigilant à ne passer dans ce script que des photos d’un même objet, dont la netteté varie.

 

Comparatif ionic / Kivy – match retour

Introduction

Suite à l’article visant à comparer ionic et Kyvi, je suis allé plus loin dans la création d’une application mobile avec ionic (ben oui, je lui ai donné une bonne note, alors j’ai creusé !). Finalement, je vais pouvoir appuyer mes propos sur des exemples concrets, en faisant une deuxième copie d’une application Kivy, mais avec ionic (écrans proches et fonctionnalités similaires).

Pour rappel, le framework ionic part d’une bonne base : utiliser les connaissances d’un développeur web pour faire des applications mobiles. Il s’avère que (à mon avis) Kivy s’en sort mieux, même avec ses points faibles. Voici les notes du match retour, sur 20.

 

Comparatif de l’installation

Notes du match aller : Kivy 18/20 ; ionic : 15/20

Après plusieurs applications créées avec ionic, ces notes ne changent pas. La documentation des débutants servira pour les prochains développements. Je trouve relativement dommage que les fichiers de configuration des plates-formes soient avec le projet. On n’est plus dans le crossplatform (ou « platform independant ») dès le début, mais on va s’arranger avec les plates-formes cibles.

Verdict : Kivy 18/20 ; ionic : 15/20

 

Editeur de code (ou IDE)

Notes du match aller : 18/20 pour les deux

Même avec Eclipse et des plugins (JS, HTML, CSS), je n’ai pas réussi à configurer rapidement l’IDE sur un projet ionic pour me faire gagner plus de temps qu’un simple éditeur de texte avec coloration syntaxique (genre Notepad++). Les recherches de dépendances (F3, CRTL-Clic) ne fonctionnent pas, c’est la cata. Heureusement que les applications sont simples.

Avec Eclipse, les classes Phyton sont reconnues et facilement retrouvées. Il ne manque que l’interprétation du langage kv pour avoir un 20/20.

Verdict : Kivy 18/20 ; ionic : 10/20

 

Documentation et exemples

Notes du match aller : 18/20 pour les deux

Après quelques écueils, je doit reconnaître que la documentation ionic (cordova et ses copains) ne sont pas si facilement applicables. Des exemples et explications sont disponibles, mais il faut mettre la frontale. De longues recherches et tests sont nécessaires pour investiguer sur un terrain inconnu. Gare aux culs de sac.

Verdict : Kivy 18/20 ; ionic : 15/20

 

Le premier « Hello world »

Notes du match aller : Kivy 18/20 ; ionic : 15/20

Attention, si on part avec de mauvaises bases et structuration du code, ca devient vite un gros bordel. Le framework ne cadre pas du tout les composants (Services, Factory, Modèles, etc) : tout peut être dans un seul fichier de 600 ko de code. Pour débuter avec une première application, ces bases sont presque obligatoires (par exemple avec CodeIgniter en PHP, qui est un régal à comparer d’ionic). Je trouve dommage que les exemples « clé en main » soient dépourvus de cette structuration.

Kivy propose plus de contrainte, car il se base sur Python qui défini déjà des packages et des modules (ce qui doit aider grandement Eclipse à retrouver les sources des classes).

Verdict : Kivy 18/20 ; ionic : 12/20

 

Développement d’une application sur un PC

Notes du match aller : Kivy 18/20 ; ionic : 12/20

Pour ce cas, je pense avoir plutôt bien jugé mes notes. Le développement est relativement laborieux avec ionic. Heureusement qu’avec un plugin pour Chrome, on arrive à avoir un rendu potable et avancer dans la création des applications. Les logs sont dans la console Javascript du navigateur, mais il n’y a pas tout. Comparé à Kivy, où tout sort dans la console d’Eclipse, c’est bien moins confortable.

Verdict : Kivy 18/20 ; ionic : 12/20

 

Déploiement sur mobile (Android)

Notes du match aller : 18/20 pour les deux

Avec ionic, on peut profiter du live-reload pour pallier aux problèmes d’utilisation des ressources présentes uniquement sur le device (ex: Base de données SQLite). Le déploiement est facile pour les deux frameworks, même avec une structuration complexe et des fichiers divers.

Verdict : 18/20 pour les deux

 

Développements sans appels au device

Notes du match aller : 18/20 pour les deux

Les développements ionic nécessitent une « boite » simulant le mobile. C’est faisable avec un navigateur comme Chromium et un plugin ;  c’est un peu bricolé. Avec Kivy, c’est une vraie fenêtre de l’OS qui s’ouvre.

Verdict : Kivy 18/20 ; ionic : 15/20

 

Appels aux fonctionnalités du device

Notes du match aller : Kivy 12/20 ; ionic : 18/20

Le désenchantement d’ionic continue lors de développements faisant appel au fonctionnalités du device (GPS, Base de données, caméra, etc.). Il n’est plus possible de se passer d’un device et de tout tester sur le mobile. On arrive aux limites de la magie du crossplatform. Il en fallait bien quelques unes, ce n’est pas du code natif et il n’y a pas de façade pour s’en abstraire (ca commence à arriver sur Kivy).

Verdict : Kivy 12/20 ; ionic : 12/20

 

Design et interface

Notes du match aller : Kivy 4/20 ; ionic : 18/20

Sauf nouveauté coté Kivy, ionic reste très pratique pour les interfaces nécessitant un design très travaillé.

Avec des widgets prédéfinis et réutilisables (et paramétrables), Kivy sort quand même la tête hors de l’eau, sans avoir de solution miracle. Il faut donc prévoir de faire des interfaces simples avec Kivy…

Verdict : Kivy 8/20 ; ionic : 18/20

 

Conclusion

Voici un rappel des notes obtenu par nos deux coureurs :

  • Installation : Kivy 18/20 ; ionic : 15/20
  • IDE : Kivy 18/20 ; ionic : 10/20
  • Documentation : Kivy 18/20 ; ionic : 15/20
  • Hello World : Kivy : 18/20 ; ionic : 12/20
  • Développement sur PC : Kivy 18/20 ; ionic : 12/20
  • Déploiement sur mobile : 18/20 pour les deux
  • Développements sans appels aux device : Kivy 18/20 ; ionic : 15/20
  • Appels aux fonctionnalités du device : Kivy 12/20 ; ionic : 12/20
  • Design et interface : Kivy 8/20 ; ionic : 18/20

Total (après utilisation plus approfondie) : Kivy 146 pts (+4 pts) ; ionic : 127 pts (-23pts)

Pour ma prochaine application mobile, si l’interface doit être simple, elle sera en Kivy. Si elle doit avoir une interface plus travaillée, ce sera avec ionic, mais elle ne sera pas trop complexe (fonctions simples).