Formulaire contact et envoi Mail

page classique d’un site web , le formulaire de contact qui permet a une personne de se renseigner et contacter l’administrateur. nous allons voir comment mettre tout ça en place .

ENVOI DE MAIL

première étape pour faire fonctionner un formulaire qui envoi un message de contact , l’envoi de mail. nous allons voir ici l’envoi SMTP avec une live box orange et une messagerie GMAIL ( le smtp utilise la messagerie gmail pour envoyer les mails).

installer un service SMTP:

nous allons ici utiliser msmtp et mta , ils ont remplacé ssmtp devenu obsolète même si c’est celui que l’on trouve le plus souvent en recherche google.

sudo apt-get install msmtp msmtp-mta

configurer la sécurité de gmail et generer un mot de passe d’application:

la sécurité de gmail doit être configurée pour generer un mot de passe utilisable dans le fichier de config (point suivant)

ouvrez votre compte gmail correspondant au mail gmail utilisé par la suite et cliquez dans l’option « securité » du menu du compte:

ensuite aller dans la fenêtre « connexion a google » , vous devriez normalement avoir l’option « validation en 2 étapes » d’activée . si ce n’est pas le cas il faudra l’activer pour pouvoir profiter de la génération d’un mot de passe d’applications extérieures accédant a la boite gmail. cliquez dans la case mot de passe des applications.

ensuite il faudra ressaisir votre identifiant et votre mot de passe puis saisir le code reçu sur votre smartphone par sms ( issu de la validation en 2 étapes) vous aurez ainsi une fenêtre du type ci dessous:

dans « sélectionner une application » choisir « messagerie » et dans » sélectionner un appareil », choisissez « autre » et saisissez un nom , par exemple « raspberri pi » puis cliquez sur la case bleu « GENERER », une fenêtre s’ouvre avec une serie de 4 valeurs comme ci dessous (exemple).

notez ces valeurs sur un papier , il faudra les mettre dans « passwordgmail » du fichier de configuration(point suivant).

configurer le SMTP pour utilisation via GMAIL:

une fois le paquet msmtp installé et le mot de passe gmail généré , il va falloir créer un fichier de config appelé msmtprc dans lequel on va spécifier un certain nombre de données et paramètres utiles a msmtp et permettant la redirection via gmail. le fichier doit être installé dans le répertoire raspberry Pi « /etc« . voici la commande shell pour créer ce fichier:

sudo nano /etc/msmtprc

voici ci dessous, un contenu basique , version passe partout (qui fonctionne bien dans mon cas) a mettre dans ce fichier config avec l’éditeur nano , il comporte un compte (account) nommé « default » qui sera utilisé pour l’envoi de mail . le « passwordgmail » a utiliser est celui généré par gmail dans le point précédent.

account default
host smtp.gmail.com
protocol smtp
auth on
user moncompte@gmail.com
password: passwordgmail
tls on
tls_starttls on
from moncompte@gmail.com
maildomain gmail.com
port 587

TEST SMTP

il reste maintenant a tester le fonctionnement de l’envoi de messages mail avec msmtp. pour cela nous allons créer un petit fichier message dans le répertoire /etc avec nano:

sudo nano etc/demo_email

dont voici le contenu

from: Name <monmail@gmail.com>
to: <destinataire@toto.fr>
subject: Test
ceci est la premiere ligne
​​​​​​​ceci est la deuxieme ligne

commande Shell de test d’envoi mail du message

reste a taper une commande shell pour envoyer le contenu du fichier .le mot « default » correspond au compte « defaut » du fichier de config « msmtprc » plus haut . il est possible de créer plusieurs comptes dans msmtprc de façon a envoyer differents mail via differents comptes .

cat demo_email | msmtp -a default destinataire@toto.fr

si vous ouvrez votre boite mail destinataire , vous devriez trouver un mail avec le contenu du fichier demo_email.

envoi de mail avec pièces jointes :

en utilisant la commande ci dessous positionné dans un répertoire comportant un fichier « filename.ext »

/Downloads $ mutt -a filename.ext -s "fichier" --destinataire@toto.fr

on envoi un mail avec le fichier joint.

FORMULAIRE DE CONTACT

première chose a faire , une petite page html permettant d’afficher un formulaire et de saisir le texte dans les case avec un bouton « Envoyer« 

le code html du formulaire :

<HTML>
<HEAD>
<TITLE>E-Mail Formulaire</TITLE>
</HEAD>
<BODY>
<FORM method="POST" action="envoi.php">
<P>Votre nom:<br>
<INPUT type="text" name="nom" size=30>
</p>
<P>Votre adresse E-Mail:<br>
<INPUT type="text" name="email" size=30>
</p>
<P>Message:<br>
<textarea name="message" cols=30 rows=5></textarea>
</p><INPUT type="submit" value="Envoyer">
</FORM>
</BODY>
</HTML>

le resultat:

et le fichier php qui envoi le contenu :

STATION METEO Arduino basique

petit montage a base d’ ARDUINO pour faire une station météo avec 3 fonctions basiques: température , pression et hygrométrie et une fonction d’enregistrement des données sur carte SD.

MATERIEL:

  • un Arduino Uno
  • un SD RTC shield (DeekRobot ou Adafruit)
  • une carte SD
  • un module DHT 22
  • un module BMP280
  • alimentation par pile 9V et cordon jack

SD RTC SHIELD:

sa fonction est de proposer sur un shield les fonctions lecture/écriture sur carte SD ainsi qu’une horloge temps réelle a pile de sauvegarde. cette carte a été abordée de façon plus détaillée ici .

le module DHT 22

c’est le même type de module que le DHT11 utilisé en exemple dans la rubrique ARDUINO SD RTC shiel mais avec des caractéristiques plus performantes ( plage de température et précision). comme le DHT 11 , il délivre la température et l’hygrométrie

le module BMP280

le module BMP280 délivre lui 2 informations ; une température et une pression

CABLAGE

broche out du DHT22 sur la broche 2 de l’arduino et Vcc et GND sur 5V et GND arduino

pour le BMP280, nous allons l’utiliser en mode I2C . il faut donc brancher GND et Vcc sur GND et 5V arduino et SCL et SDA du BMP280 sur les broche SCL et SDA de l’arduino uno . l’arduino UNO possede 2 paires de broches I2C ( SCL + SDA)=> voir le pinout ICI

le SD RTC shield doit etre « pluggué » sur l’arduino UNO puis les 2 composants (DHT22 et BMP280) ainsi que la pile reliés a l’UNO ( le SD shield n’est pas représenté sur le schéma fritzing ci dessus) : pour le DHT22 et le BMP280 , utiliser une petite platine proto .

NOTA: attention, une pile type 9V ne permet un fonctionnement que de quelques heures. pour une station météo d’observatoire , il faudra soit une alim secteur soit une alim batterie sur panneau solaire.

PROGRAMME ARDUINO

le programme est un « melting-pot » de plusieurs programmes d’exemples joints avec les différentes librairies utilisées.

très synthétiquement, on charge les différentes librairies nécessaires ( wire.h pour l’I2C, SPI.h pour le lecteur SD, SD.h pour l’utilisation de la carte SD, RTClib.h pour l’horloge temps réel, Adafruit_BMP.h pour le BMP280, DHT.H pour le DHT22), puis on defini quelques constante et brochage . le programme void setup lance les differentes fonctions et parametres liées aux librairies, la boucle « void loop » lit les données des capteurs et les stocke dans des variables ainsi que année, mois, jour et heures/minutes/secondes de l’horloge RTC.

pour la temperature , on recuperer les 2 temperatures t1 et t2 des 2 capteurs et on calcule la moyenne des 2 => ligne  » tm = (t1+t2)/2« 

une serie de parametres « filename[x] permet de definir chaque caractère du nom de fichier d’enregistrement des données => un fichier par jour de l’année suivant la syntaxe : année mois jour. puis le fichier est ouvert , les données enregistrées dedans sous forme string CSV et le fichier est refermé , le programme attends 60 secondes puis recommence => un enregistrement de données toutes les minutes.

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <RTClib.h>
#include <Adafruit_BMP280.h>
#include "DHT.h"
const int chipSelect = 10;
#define DHTPIN 2 
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
RTC_DS1307 RTC;
Adafruit_BMP280 bmp; // I2C

char filename [] = "00000000.CSV";

void setup() {
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  // ligne suivante pour initialiser l'heure du RTC/PC  la premiere fois 
  // decocher les // , telecharger , puis remettre les // 
  // RTC.adjust(DateTime(__DATE__, __TIME__));
  dht.begin();
  bmp.begin(); 
   /* config par defaut suivant datasheet */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     
                  Adafruit_BMP280::SAMPLING_X2,     
                  Adafruit_BMP280::SAMPLING_X16,    
                  Adafruit_BMP280::FILTER_X16,     
                  Adafruit_BMP280::STANDBY_MS_500); 
  SD.begin(chipSelect);               
}

void loop() { 
  float h = dht.readHumidity();
  float t1 = dht.readTemperature();
  float t2 = bmp.readTemperature();
  float p = bmp.readPressure();
  float  tm = (t1+t2)/2 ;   
  DateTime now = RTC.now();
  uint16_t year1 = now.year();
  uint16_t month1 = now.month();
  uint16_t day1 = now.day();
  uint16_t hour1 = now.hour();
  uint16_t minute1 = now.minute();
  uint16_t second1 = now.second();
  filename[0] = (year1/1000)%10 + '0';
  filename[1] = (year1/100)%10 + '0';
  filename[2] = (year1/10)%10 + '0';
  filename[3] = (year1)%10 + '0';
  filename[4] = month1/10 + '0'; 
  filename[5] = (month1)%10 + '0'; 
  filename[6] = day1/10 + '0'; 
  filename[7] = (day1)%10 + '0';
  filename[8] = '.';
  filename[9] = 'c';
  filename[10] ='s';
  filename[11] ='v';
  File dataFile = SD.open(filename, FILE_WRITE);
  String dataReg = String(year1) + "/" + String( month1) + "/" + String(day1) +";" + String(hour1) + ":"+ String(minute1) + ":" + String(second1) + ";" + String(tm) + ";" + String(h) + ";" + String(p) + ";" ; 
  dataFile.println(dataReg);
  dataFile.close();
  delay(60000);
}

voici un exemple de données enregistrées:

fichier CSV ouvert avec wordpad: date ; heure ; température ; humidité ; pression (en pascals)

le même fichier CSV ouvert avec LibreOffice ou Excel , l’enregistrement avec des « ; » séparant les paquets de données permet de récupérer chaque paquet dans une colonne différente sur le tableur.

AMELIORATION

nous allons améliorer la station météo en ajoutant un écran LCD I2C 4 lignes de 20 caractères pour y afficher , date et heure sur la première ligne, température sur la deuxième ligne , humidité et pression sur la troisième ligne. la quatrième ligne est en réserve pour la vitesse et la direction du vent .

le schéma de câblage avec l’écran I2C devient:

le programme deviens (évolutions en bleu):

#include <Wire.h>
#include <SPI.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <RTClib.h>
#include <Adafruit_BMP280.h>
#include "DHT.h"
const int chipSelect = 10;
#define DHTPIN 2 
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
RTC_DS1307 RTC;
Adafruit_BMP280 bmp; // I2C
LiquidCrystal_I2C lcd(0x27,20,4);
char filename [] = "00000000.CSV";
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  Wire.begin();
  RTC.begin();
  // ligne suivante pour initialiser l'heure du RTC/PC  la premiere fois 
  // decocher les // , telecharger , puis remettre les // 
  // RTC.adjust(DateTime(__DATE__, __TIME__));
  dht.begin();
  bmp.begin(); 
   /* config par defaut suivant datasheet */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     
                  Adafruit_BMP280::SAMPLING_X2,     
                  Adafruit_BMP280::SAMPLING_X16,    
                  Adafruit_BMP280::FILTER_X16,     
                  Adafruit_BMP280::STANDBY_MS_500); 
  SD.begin(chipSelect);               
}
void loop() { 
  float h = dht.readHumidity();
  float t1 = dht.readTemperature();
  float t2 = bmp.readTemperature();
  float p = bmp.readPressure();
  float tm = (t1+t2)/2;  
  DateTime now = RTC.now();
  uint16_t year1 = now.year();
  uint16_t month1 = now.month();
  uint16_t day1 = now.day();
  uint16_t hour1 = now.hour();
  uint16_t minute1 = now.minute();
  uint16_t second1 = now.second();
  filename[0] = (year1/1000)%10 + '0';
  filename[1] = (year1/100)%10 + '0';
  filename[2] = (year1/10)%10 + '0';
  filename[3] = (year1)%10 + '0';
  filename[4] = month1/10 + '0'; 
  filename[5] = (month1)%10 + '0'; 
  filename[6] = day1/10 + '0'; 
  filename[7] = (day1)%10 + '0';
  filename[8] = '.';
  filename[9] = 'c';
  filename[10] ='s';
  filename[11] ='v';  
  String date = String(day1) + "/" + String(month1) + "/" + String(year1);
  String time = String(hour1) + ":" + String(minute1) + ":" + String(second1);
  lcd.setCursor(0,0);
  lcd.print(date) ;
  lcd.setCursor(11,0);
  lcd.print(time) ;
  lcd.setCursor(7,1);
  lcd.print(tm) ; 
  lcd.setCursor(12,1);
  lcd.print(char(223)) ;
  lcd.setCursor(13,1);
  lcd.print("C") ;     
  lcd.setCursor(0,2);
  lcd.print(h) ;
  lcd.setCursor(5,2);
  lcd.print("%Hu") ; 
  int roundp =  int(p);
  lcd.setCursor(9,2);
  lcd.print(p) ;
  lcd.setCursor(18,2);
  lcd.print("Pa") ;  
  File dataFile = SD.open(filename, FILE_WRITE);
  String dataReg = String(year1) + "/" + String( month1) + "/" + String(day1) +";" + String(hour1) + ":"+ String(minute1) + ":" + String(second1) + ";" + String(tm) + ";" + String(h) + ";" + String(p) + ";" ; 
  dataFile.println(dataReg);
  dataFile.close();
  delay(60000);
}

et visuellement , le montage fini en fonctionnement , ressemble a cela:

la version finale de la station integrera un anemometre et une girouette

pour rendre la station autonome , elle sera alimentée par un panneau solaire 12V – 5 watts alimentant une batterie 12V.

STATION METEO SERVEUR

une station météo ARDUINO en réseau privé via votre BOX c’est possible avec un Ethernet Shield . nous allons voir comment.

le tuto est basé sur l’utilisation d’un Shield ethernet Keyestudio mais le principe est le même avec d’autre shield Ethernet. l’avantage du shield Keyestudio est qu’il comporte en plus un slot pour carte micros SD. outre la transmission Ethernet des données, il sera donc également possible de les sauvegarder sur carte micro SD.

petit problème global avec les Shield Ethernet , contrairement au shiel SD , ils n’ont pas d’Horloge RTC intégrée , il va donc falloir en ajouter une. dans ce tuto , on utilisera un module TinyRTC I2C. mais tout autre module RTC peut convenir.

par ailleurs , nous allons profiter de ce module pour notre premier exemple de transmission de données via câble réseau Ethernet en affichant tout simplement la date et l’heure récupérée sur le module dans une page de navigateur .

LE MONTAGE :

pas besoin de schéma fritzing , ici la connexion est simple , on relie les broche Vcc et GND du module RTC aux borches GND et 5V de l’arduino uno et les broches SCL et SDA respectivement au broche Analogiques A5 et A4 de l’Arduino UNO.

LE PROGRAMME :

#include <SPI.h>
#include <Ethernet.h>
#include "RTClib.h"
RTC_DS1307 rtc;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
EthernetServer server(80);

void setup() {
  rtc.begin();
  SPI.begin();
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop() {  
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
          DateTime time = rtc.now();
          client.print("DATE: ");
          client.println(time.timestamp(DateTime::TIMESTAMP_DATE));
          client.print("TIME: ");
          client.println(time.timestamp(DateTime::TIMESTAMP_TIME));
          break;
     }
    delay(100);
    client.stop();
  }
}

les librairies sont standard , si pas disponibles dans votre IDE , une petite recherche internet vous permettra de les récupérer. en début de programme , via les instruction byte mac[] et IPadress on fixe l’adresse Mac et l’adresse IP du shield ( a modifier suivant les données de votre Box internet) . ensuite la partie void setup , démarre les librairies , et la partie void loop ouvre le serveur puis la boucle while exécute les lignes suivantes tant que la connexion est OK . dans la boucle on lit les données date et heure du module TinyRTC puis on les imprime sur le serveur client via une instruction type « client.print() « 

ne reste plus qu’a lire tout ça a l’adresse IP avec un navigateur Web . pas très compliqué , ouvrir votre navigateur préféré et tapez l’adresse IP (ici 192.168.1.15) et vous devriez voir apparaitre quelque chose comme ci dessous:

bien entendu , si vous utilisez votre smartphone connecté en WIFI a votre réseau domestique, ça marche aussi avec l’explorateur web du smartphone.

le problème avec l’affichage obtenu c’est que la structure est extrêmement minimale et surtout la page ne se régénère pas automatiquement , il faut la régénère à la main pour voire l’heure évoluer.

nous allons donc mettre en place une page web basique en HTML avec régénération automatique. et rajouter des test pour la connexion. le programme plus bas est une modification pure et simple d’un programme exemple livré avec la bibliothèque « Ethernet.h » que l’on trouve sous l’IDE ARDUINO dans le chemin:

Fichier/example/Ethernet/Webserver

STRUCTURE MINIMALE D’UNE PAGE HTML

première chose a intégrer , la structure minimale standard obligatoire d’une page web en HTML . ci dessous un petit schéma qui montre les éléments (balises) constitutifs d’une page web standard minimale.

  • <!DOCTYPE html> est la balise qui précise le langage utilisé .
  • <html> est la balise délimite le début la zone de contenu html
  • </html> est la balise qui symbolise la fin de la zone html
  • a l’intérieur de cette zone html , on va trouver deux types de balises:
  • <head> et </head> pour définir debut et fin de la zone des données d’entête
  • <body> et</body> qui délimitent la zone de texte (corps) de la page web

la zone d’entête doit comporter le titre de la page entre les balises <title> et </title>

et le type d’encodage utilisé ici <meta charset= »utf-8″>

petite particularité , sous C++ ARDUINO , concernant la rédaction, il faudra écrire:

<meta charset=\ »utf-8\ »> </meta>

pour demander la régénération de la page , il faudra insérer « Refresh: x«  avec X le temps de rafraichissement.

passons au programme modifié avec en violet les rajouts par rapport au programme initial .

#include <SPI.h>
#include <Ethernet.h>
#include "RTClib.h"
RTC_DS1307 rtc;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
EthernetServer server(80);

void setup() {
  rtc.begin();
  SPI.begin();
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop() {  
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // cloture connexion
          client.println("Refresh: 10");  // rafraichissement de page toute les 10s
          client.println();
          client.println("<!DOCTYPE HTML>");  // specifie le type de document=HTML
          client.println("<html>");  // debut de la page
              client.println("<head>");
                  client.println("<meta charset=\"utf-8\"></meta>"); //encodage page
                  client.println("<title>METEO LOCALE</title>");  // titre de la page
              client.println("</head>");
              client.println("<body>"); // debut de zone du contenu visible
                    DateTime time = rtc.now();
                    client.print("DATE: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_DATE));
                    client.print("  TIME: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_TIME));
              client.println("</body>"); // fin de zone du contenu 
          client.println("</html>");   // fin de la page         
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1000);
    // close the connection:
    client.stop();
  }
}

une fois le programme déversé dans l’arduino , si l’on ouvre le navigateur et que l’on saisi l’adresse 192.168.1.15 , voici ce que donne l’affichage :

on remarque que maintenant la page a un titre « METEO LOCALE » , date et heure sont sur la même ligne et sont mises a jour toutes les 10″ ( seule l’heure varie apres mise a jour).

AJOUT DES CAPTEURS METEO

pour l’étape suivante , ne reste plus qu’a connecter vos capteur météo, pour changer de la version développée ici , nous allons simplifier le montage et remplacer les 2 capteur DHT22 et BMP280 , par un capteur BME280 qui intègre les 3 fonctions; température, pression et Humidité sur un seul module .

c’est un capteur I2C dont le câblage sera donc extrêmement simple, il viendra en parallèle de l’Horloge RTC elle même branchée sur l’I2C. comme toujours avec l’I2C , il faudra contrôler les adresses I2C de chaque composant ( Ici 0x76 pour le capteur BME280 et 0x50 pour l’horloge RTC) et vérifier dans les fichiers des bibliothèques utilisées que les adresses sont les bonnes et faire les modif le cas échéant).

pour cela , on ouvre la bibliotheque « SParFunBME.h » et son fichier complémentaire « SparkFunBME280.cpp » avec un simple editeur de texte genre blocnote de windows, on découvre en general que l’adresse I2C dans la librairie CPP est 0x77 . il faut donc la remplacer par 0x76 et enregistrer le fichier . puis on recompile/televerse le pgme dans l’arduino qui pilote le montage de façon a recuperer la bonne adresse I2C pour le compileur du pgme.

NOTA: la librairie BME280 est en general dans le repertoire « user/nomuser/documents/arduino/librairies ».

voyons maintenant le programme :

par rapport a la version précédente du programme , en violet les ajouts/évolutions concernant le capteur , et pour rendre les données plus visible sur la page , la taille des caractères a été augmentée => ajout d’une ligne  » client.print(« <font size=’10’> »); « 

pour aérer la page , chaque information est affichée sur une ligne différente , le saut de ligne se fait par l’envoi d’un client.print(« <br/> »);

#include <Wire.h>
#include <SPI.h>
#include <Ethernet.h>
#include "RTClib.h"
#include <SparkFunBME280.h>
RTC_DS1307 rtc;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
BME280 mySensor;
EthernetServer server(80);

void setup() {
  Wire.begin();
  rtc.begin();
  SPI.begin();
  Ethernet.begin(mac, ip);
  server.begin();
  mySensor.beginI2C();
}

void loop() {  
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  
          client.println("Refresh: 10");  
          client.println();
          client.println("<!DOCTYPE HTML>");  
          client.println("<html>");  
              client.println("<head>");
                  client.println("<meta charset=\"utf-8\"></meta>");
                  client.println("<title>METEO LOCALE</title>");     
              client.println("</head>");
              client.println("<body>"); 
                    DateTime time = rtc.now();
                    client.print("<font size='10'>");
                    client.print("Date: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_DATE));
                    client.print("<br/>");
                    client.print("heure: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_TIME));
                    client.print("<br/>");
                    client.print("temperature: ");
                    client.print(mySensor.readTempC());
                    client.print("<br/>");
                    client.print("pression: ");
                    client.print(mySensor.readFloatPressure());
                    client.print("<br/>");
                    client.print("Humidité: ");
                    client.print(mySensor.readFloatHumidity());        
              client.println("</body>"); 
          client.println("</html>");   
          break;
        }
        if (c == '\n') {
                   currentLineIsBlank = true;
        } else if (c != '\r') {
                    currentLineIsBlank = false;
        }
      }
    }
    delay(1000);
    client.stop();
  }
}

si tout est OK âpres compilation et déversement dans l’ARDUINO UNO , si on ouvre le navigateur sur son PC et que l’on se connecte a l’adresse 192.168.1.15 de l’arduino uno et son ethernet shield on obtient l’affichage ci dessous qui se rafraichis automatiquement toutes les 5 secondes :

STATION METEO CLIENT

après la version serveur , voyons maintenant la station client qui envoie les données a une page PHP pour enregistrer les données dans une Base De Données MySQML. on peut ensuite consulter la base de donnée ou effectuer des operations sur celle si a partir d’un site internet.

nous allons ici utiliser 3 programmes:

  • un programmeArduino: « meteoclient.ino » ( arduino uno muni de son shield ethernet) qui envoie les données capteurs a une page PHP nomée « insert.php »localisée sur le RPI en mode serveur.
  • la page php « insert.php » qui récupère les infos et les transmet a une base de donnée Mysql nomée « meteo » avec une table nommée « tablemeteo« .
  • une page php « viewtable.php » pour visualiser le contenu de la table de données .

MISE EN PLACE DE LA BDD MySQL et de sa TABLE:

a l’aide de PhpMyAdmin, nous allons créer la base de donnée nomée « meteo » et sa table « tablemeteo » dont voici la structure :

PROGRAMME ARDUINO :

pour le montage Arduino , nous allons reprendre l’ensemble décrit ICI .

  • arduino UNO + Ethernet shield
  • horloge temps reel TinyRTC I2C
  • capteur température/pression/humidité I2C BME280

le programme charge les librairies adéquates, les ouvre , configure l’adresse mac et IP du shield ethernet ( ici 192.168.1.15) puis dans la boucle void , récupère l’heure et la date du RTC puis les valeurs température , pression et humidité du capteur puis envoie tout ça au serveur RPI (adresse IP 192.168.1.18 port 80) et au fichier php « insert.php« en utilisant une syntaxe du type ci dessous:

insert.php?id=0&date=2021-10-12&heure=14:14:25&temperature=25&pression=1028&humidite=66

NOTA: la derniere ligne  » client.print(« \r\n »);  » est primordiale, elle effectue un double retour chariot, sans cette commande , l’envoi des données n’est pas opérant.

#include <Wire.h>
#include <SPI.h>
#include <Ethernet.h>
#include "RTClib.h"
#include <SparkFunBME280.h>
RTC_DS1307 rtc;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
BME280 mySensor;
EthernetClient client;
int id1 = 0;
String date1 ="";
String heure1 ="";
float temperature1 =0;
float pression1 = 0;
float humidite1 =0;

void setup() {
  Serial.begin(9600);
  Serial.println("demarrage");
  Wire.begin();
  rtc.begin();
  SPI.begin();
  mySensor.beginI2C();
  Ethernet.begin(mac, ip);
}

void loop() {
  if (client.connect("192.168.1.18", 80)) {
    DateTime time = rtc.now();
    date1 = time.timestamp(DateTime::TIMESTAMP_DATE);
    heure1 = time.timestamp(DateTime::TIMESTAMP_TIME);
    temperature1 = mySensor.readTempC();
    pression1 = mySensor.readFloatPressure();
    humidite1 = mySensor.readFloatHumidity();
    client.print( "GET /insert.php?id=");
    client.print("0");    
    client.print("&date=");    
    client.print(date1);
    client.print("&heure=");
    client.print(heure1);
    client.print("&temperature=");
    client.print(temperature1);
    client.print("&pression=");
    client.print(pression1);
    client.print("&humidite=");
    client.print(humidite1);
    client.print("\r\n");
    delay(30000);     
  } else {
    Serial.println("echec de la connexion");
    delay(3000);
  }
}

PROGRAMME PHP de transfert ARDUINO => MySQL:

le programme php lui est extrêmement simple: le fichier ci dessous devra etre sauvegardé avec l’extension php au lieu de txt dans le répertoire var/www/html du RPI.

en premiere ligne il se connecte a la BDD « meteo » sur le serveur local avec l’identifiant « root » , le mot de passe « motdepasse » ( ces paramètres sont éventuellement a changer en fonction des vôtres).

en deuxième ligne il envoi la commande d’insertion des paramètres arduino .

la ligne « mysqli_query ($dbconnect,$sql); » effectue la requête de connexion et d’envoi des données.

<?php
$dbconnect = mysqli_connect("localhost", "root", "motdepasse", "meteo"); 
$sql = "INSERT INTO tablemeteo (id, date, heure, temperature, pression, humidite) VALUES ('".$_GET['id']."', '".$_GET['date']."', '".$_GET['heure']."', '".$_GET['temperature']."', '".$_GET['pression']."', '".$_GET['humidite']."')";
mysqli_query($dbconnect,$sql);
?>

VISUALISATION DU RESULTAT :

pour visualiser le résultat de l’envoi des données a la table de la BDD meteo , nous allons ajouter un script php dans le répertoire var/www/html du RPI.

le fichier ci dessous au format .txt devra y etre copié avec l’extension.php

<?php
$link = mysqli_connect("localhost", "root", "motdepasse", "meteo");
if($link === false){
    die("ERROR: Could not connect. " . mysqli_connect_error());
}
$sql = "SELECT * FROM tablemeteo";
if($result = mysqli_query($link, $sql)){
    if(mysqli_num_rows($result) > 0){
        echo "<table>";
            echo "<tr>";
                echo "<th>ID</th>";
                echo "<th>DATE</th>";
                echo "<th>HEURE</th>";
                echo "<th>TEMPERATURE</th>";
		echo "<th>PRESSION</th>";
		echo "<th>HUMIDITE</th>";
            echo "</tr>";
        while($row = mysqli_fetch_array($result)){
            echo "<tr>";
                echo "<td>" . $row['id'] . "</td>";
                echo "<td>" . $row['date'] . "</td>";
                echo "<td>" . $row['heure'] . "</td>";
                echo "<td>" . $row['temperature'] . "</td>";
                echo "<td>" . $row['pression'] . "</td>";
                echo "<td>" . $row['humidite'] . "</td>";
            echo "</tr>";
        }
        echo "</table>";
        // Free result set
        mysqli_free_result($result);
    } else{
        echo "No records matching your query were found.";
    }
} else{
    echo "ERROR: Could not able to execute $sql. " . mysqli_error($link);
}
mysqli_close($link);
?>

une fois positionné dans le répertoire du RPI , pour se connecter a la table, il suffit d’ouvrir votre navigateur internet sur votre PC connecté au réseau et de taper:

192.168.1.18/viewtable.php

si tout est ok vous devriez voir une page de ce type : attention , la page ne se régénère pas automatiquement , il faut l’actualiser a la main pour voir le nombre de lignes évoluer au fil du temps .

une petite vidéo YouTube qui résume tout ça :

communication serie PI <=> ARDUINO

voyons ici quelques bases pour la communication serie bidirectionnele entre un Raspberry PI et un arduino UNO .

ce sujet est abordé brièvement ici mais uniquement sur l’aspect communication unidirectionnelle de l’arduino vers le raspberry Pi pour la réception de données et l’enregistrement sur le raspberry PI . nous allons essayer, ici, de le compléter avec quelques exemples centrés sur la communication bidirectionnelle dans le but d’instaurer des échanges type action/réaction entre les deux , cela a un interet par exemple pour les dialogue RPI <=> station meteo Arduino, pour les interaction electromecaniques ( arduino pilote des actionneurs et RPI envoi les commandes et sert d’interface homme machine pour gerer les menus et interactions ecran/claviers/souris/etc..)

EXEMPLE 1:

le premier exemple sera très simple, le RPI envoie un message a l’Arduino qui lui réponds, pour cela installer les 2 programmes ci dessous respectivement sur votre ARDUINO et votre Raspberry PI :

void setup() {
    Serial.begin(9600);
}

void loop() {
  if (Serial.available()>0) {
    String data=Serial.readStringUntil('\n');
    Serial.print("message reçu: ");
    Serial.println(data);
  }
}
import serial
import time
ser=serial.Serial(port='/dev/ttyACM0',baudrate=9600, timeout=0.2)

while True:
    ser.write(b"Coucou du RPI4\n")
    line=ser.readline().decode('utf-8').rstrip()
    print(line)
    time.sleep(1)

le programme C++ arduino , « ecoute » les données qui arrive sur le port série et renvoi sur celui ci le message « message reçu: » avec derriere le message reçu du RPI.

le programme Python du RPI , envoi sur le port USB le message « Coucou du RPI4 » avec un retour chariot (\n) puis met dans la variable « line » ce qu’il lit en retour de l’arduino puis l’imprime (print(line) et attends 1 seconde avant de recommencer. voici ci dessous petite copie d’ecran des 2 programmes ouverts sur le RPI4 avec le résultat du lancement du pgme python qui s’affiche dans la fenêtre shell de thonny python.

EXEMPLE 2:

a partir du meme programme arduino que plus haut , a titre didactique, nous allons reprendre les bases du deuxième exemple de la rubrique « evenement CLAVIER SOURIS » pour batir un programme qui envoi a l’arduino des valeurs de mouvements x et Y sous forme de chaine de caractères et lit en retour le message renvoyé par l’arduino (à savoir la commande envoyée qui est retournée par l’arduino)

import tkinter as tk
root=tk.Tk()
root.geometry("500x500+450+100")
canvas1=tk.Canvas(root, width=500, heigh=500)
canvas1.pack()
command='M00'
def keypressed(k):
    x=0
    y=0
    global command
    if k.keysym=='Up':
        y=-1
    if k.keysym=='Down':
        y=1
    if k.keysym=='Left':
        x=-1
    if k.keysym=='Right':
        x=1
    command='M'+str(x)+str(y) 
    ser.write(command.encode('utf-8'))
    line=ser.readline().decode('utf-8').rstrip()
    print(line)
root.bind('<KeyPress>', keypressed)
root.mainloop()

la commande envoyée est de la forme Mxy avec x et y des valeurs de déplacements valant +1 ou -1 sous forme de caractères . il est asses facile ensuite de demander au programme Arduino de décoder ces 2 valeurs et les transformer par exemple en valeur Step pour commander un moteur pas a pas branché sur l’Arduino. même principe pour commander la rotation d’un moteur . on pourrait également demander a l’Arduino de retourner une valeur de fin de course ou de capteur sous forme de chaine type Cab (C pour capteur et a/b pour les valeurs a prendre en compte). avec ce type de principe il est donc facile de mettre en place un protocole de communication aller/retour et traiter chaque information de chaque coté en fonction du code de commande associé a la première lettre …

évènements CLAVIER et SOURIS avec TK inter

dans un programme python sur raspberry pi pour des appli astro il peut être intéressant d’utiliser clavier et souris pour des commandes spécifiques autre que de la saisie de données. par exemple, utiliser les touches fleches du clavier pour commander des mouvements de moteurs pas a pas sur une monture équatoriale motorisée.

nous allons voir ici les bases de la gestion des événements clavier et souris avec Tkinter.

EXEMPLE BASIQUE:

les quelques lignes de python ci dessous permettent d’exploiter de façon tres basique la gestion des evenements clavier et souris avec Tkinter. a noter que cela fonctionne egalement avec les clavier avec track pad reconnus comme une souris par Tkinter.

import tkinter as tk

def keypressed(k):
    print(k.keysym, k.keycode)
def mouse(m):
    print(m)
def button(b):
    print(b)
      
root=tk.Tk()
root.geometry("500x500+400+100")
root.bind('<KeyPress>', keypressed)
root.bind('<Motion>', mouse)
root.bind('<Button>',button)

root.mainloop()

dans le programme , on defini une fenetre « root=tk.Tk() » avec TKinter, ainsi que sa géometrie (largeur/hauteur :500×500 et position x/Y: 400+100) via la ligne :

root.geometrie(« 500×500+400+100 »)

la partie « stratégique » de ce bout de python est constituée des 3 lignes « root.bind()« . avec les 3 fonction bind permettant chacune d’associer des événements a des fonctions définies en début de programme. les 3 fonctions définies , impriment les paramètres des événements concernés; symbole et code de la touche clavier préssée, coordonnées X et Y de la souris dans le cadre root et bouton de souris enfoncé. voici ci dessous copie d’écran du résultat sous thonny Python avec un raspberry; le résultat des actions s’affiche dans la fenetre du shell en bas a gauche:

concernant l’architecture de la commande bind , elle est asses simple:

root.bind(‘<evenement>’, appel fonction)

ci dessous les principaux événements reconnus par Tkinter:

événements clavier:

événements souris:

a partir de ces éléments fondamentaux , il est possible ensuite d’implémenter des fonctions et actions évoluées a partir des événements souris ou clavier . par exemple, faire tourner un moteur pas a pas branché sur le GPIO du raspberry PI dans un sens ou dans l’autre avec les flèches gauche et droite du clavier (voir ici pour la commande d’un NEMA17), actionner un moteur CC d’ouverture de toiture , commander l’orientation d’une monture equatoriale, etc …

à titre d’exemple un peu plus complet , ci dessous petit programme qui bouge le caracter X , en partant du centre, dans la zone de fenetre Tkinter via les touches fleches droite -gauche-haut-bas . pour faire tourner 2 NEMA17 , il suffit d’utiliser les variables X et Y comme valeur STEP et envoyer ça sur 2 drivers Pololu A4988 via le GPIO . pas plus compliqué que ça ….

import tkinter as tk
root=tk.Tk()
root.geometry("500x500+450+100")
canvas1=tk.Canvas(root, width=500, heigh=500)
canvas1.pack()
x=250
y=250

def keypressed(k):
    global x
    global y
    if k.keysym=='Up':
        y+=-1
    if k.keysym=='Down':
        y+=1
    if k.keysym=='Left':
        x+=-1
    if k.keysym=='Right':
        x+=1
    text=tk.Label(root, text= 'X', fg='yellow', bg='blue')
    canvas1.create_window(x,y, window=text)

root.bind('<KeyPress>', keypressed)
root.mainloop()

et le resultat apres quelques appuis variés:

voila , ce sera tout pour cette rubrique sur la fonction bind() , quelques liens complémentaires utiles ci dessous :

http://tkinter.fdex.eu/doc/event.html

understanding TKinter event

Fichier NGC avec Python

en astronomie , les objets du ciel profond sont souvent désignés au travers de leur code du catalogue NGC . nous allons voir ici quelques manipulations avec Python sur le fichier NGC.

pour les exemples de programmes python , ci dessous le fichier NGC au format csv a télécharger et installer par exemple dans votre répertoire home/pi/Documents :

le format CSV , alias Comma-Separated Values , est un format texte ouvert, représentant des données tabulaires sous forme de valeurs séparées par des virgules. il est reconnu par excel , OpenOffice et LibreOffice.

les objets NGC sont enregistrés sous la forme ci dessous ( NGC0224=Andromède):

NGC0224;00:42:44.35;+41:16:08.6

chaque ligne du fichier fait 31 caractères avec un retour chariot a la fin de la ligne( non visible). on trouve dans les 7 premiers caractères la référence NGC , ensuite un point virgule derrière lequel on trouve l’ascension droite en heures:minutes:secondes (2 chiffres après la virgule), puis un nouveau point virgule puis la déclinaison en degrés, minutes, secondes (un seul chiffre après la virgule).

EXEMPLE 1: ouverture du fichier et lecture puis impression des lignes du fichier

import time
f = open("home/pi/Documents/NGC.csv", "rt")
for x in f:
	print(x)
	time.sleep(0.5)

comme souvent en python, rien de très compliqué , le fichier est stocké dans une variable f ( le fichier est considéré comme un array) via la commande open() , dans laquelle on précise le chemin d’accès et le nom, puis le type d’ouverture . la librairie time est ouverte et une ligne time.sleep() est rajoutée pour ralentir un peu le programme . ici « rt » qui veut dire Read Text soit une ouverture du fichier en mode lecture et au format text . pour écrire/enregistrer un fichier au format texte ce serait open(« nomfichier.csv », « wt ») pour write Text . ci dessous le lien vers la page Python pour les fichiers:

lien doc python

EXEMPLE 2: petite variation du programme précédent, ouverture du fichier et recherche d’une référence NGC puis impression de la ligne correspondante . ici comme on affiche une seule ligne trouvée dans le fichier , pas besoin de la librairie time ni de la ligne time.sleep()

f = open("home/pi/Documents/NGC.csv")
for x in f:
	if "NGC3200" in x:
		print(x)

encore une fois rien de compliqué , avec 4 lignes de python , on ouvre le fichier , on trouve l’enregistrement et on imprime son contenu.

EXEMPLE 3: amélioration du programme précédent , on emballe tout ça dans une petite interface graphique sous tkinter, avec fenêtre de saisie de la ref NGC et bouton de recherche a cliquer pour lancer la recherche :

import tkinter as tk
root=tk.Tk()
canvas1=tk.Canvas(root, width=400, heigh=300)
canvas1.pack()
entry1=tk.Entry(root)
canvas1.create_window(200, 140, window=entry1)

def NGCsearch():
    x1 = entry1.get()
    f = open("/home/pi/Documents/FICHIERS NGC/NGC.csv", "rt")
    for x in f:
        if x1 in x:
            label1=tk.Label(root, text= x)
            canvas1.create_window(200,230, window=label1)
button1= tk.Button(text='recherche', command=NGCsearch)
canvas1.create_window(200, 180, window=button1)

root.mainloop()

ci dessous copie d’écran du résultat après recherche de NGC0224

pour finir voici a titre d’exemple , le resultat d’un petit programme de recherche , affichage et calcul pour un module GOTO en python . on entre les references NGC de l’objet de reference ( pointé avec un viseur laser) , puis la reference NGC de l’objet cible a rechercher , le programme ouvre le fichier NGC.CSV , trouve les datas des 2 objets NGC, les affiche puis calcule les delta angulaire AD et DEC pour envoyer a la monture DIY qui fait tourner les moteurs pas a pas du nombre de pas correspondant aux valeurs d’ecarts.

PAUSES LONGUES avec une PI cam HQ

la dernière née des PI camera , outre une meilleure définition (4056 x 3040) offre la possibilité de faire des pauses longues jusqu’à 200 secondes pour l’astrophotographie du ciel profond . nous allons voir comment exploiter ces capacités .

tout d’abord petit rappel des caractéristiques des différentes PIcam dans le tableau comparatif ci dessous:

pour exploiter les capacités des Picam , il existe 2 possibilités:

  • les commandes en ligne Raspistill pour la photo et Raspivid pour la video .
  • un programme Python avec 2 options: passer des commandes raspistill ou utiliser la librairie Picam .

Pauses longues avec Raspistill

on ouvre l’éditeur de commande et on tape une instruction du genre:

raspistill -n -md 3 -awb off -ex off -ISO 800 -ss 100000000 -o PLtest01.jpg

tout ce qui est derriere « raspistill » consiste aux differentes option , ici :

  • -n inhibe la previsualisationa l’issue de la prise de vue
  • -md 3 met la Picam HQ en mode 3 (permet les pauses longues jusqu’a 200″)
  • -awb off , annule la balance des blanc
  • -ex off , annule le mode d’exposition
  • -ISO 800 : fixe la sensibilité ISO a 800 , les valeurs possibles sont 100-200-400-800. il faut avoir enlever l’exposition et la balance des blancs pour controler les ISO.
  • -ss 100000000 : fixe le Shutter Speed a 100 secondes (100000000 microsecondes)
  • -o PLtest01.jpg enregistre la photo dans le fichier « PLtest01.jpg »

pour plus d’information sur les options raspistill et raspivid , voir le fichier PDF ci dessous

attention, raspistill ne met pas a jour les donnes EXIF du fichier ….

Pauses longues avec PYTHON

methode 1 : envoyer une commande raspistill avec Python

pour envoyer une commande shell avec Python, c’est tres simple, il faut appeller la fonction subprocess .call(), en reprenant la commande plus haut cela donne:

import subprocess
cmd="raspistill -n -md 3 -awb off -ex off -ISO 800 -ss 100000000 -o PLtest01.jpg"
subprocess.call(cmd, shell=True)

bien sur avec ce principe, il est possible de parametrer des variables pour la durée de pause et rajouter une boucle while avec compteur et implementation du nom de fichier pour une sequence time laps pause longue (voir ci dessous)

methode 2 : utiliser la librairie PICAM

voyons un premier exemple basique

import picamera
from time import sleep
from fractions import Fraction
camera = picamera.PiCamera()
# camera en resolution max
camera.resolution=(4056, 3040)
# capteur en mode Pause longue (mode 3) 
camera.sensor_mode=3
# exposure mode off pour pouvoir utiliser les ISO
camera.exposure_mode = 'off'
# autowhite balance mode off pour utiliser les ISO
camera.awb_mode = 'off'
# framerate a 50s
camera.framerate =Fraction(1,50)
# vitesse d'obturation a 50 secondes
camera.shutter_speed = 50000000
#sensibilite ISO a 800 pour un gain maximum en condition nocturnes
camera.iso = 800
#prise de vue et sauvegarde sous le nom 'pauselongue.jpg'
camera.capture('pauselongue.jpg')
camera.close()

ce petit bout de python, permet de voir qu’avec quelques simples lignes de commandes python on peut déclencher une prise de vue pause longue de 50 secondes a 800 ISO et sauvegarder le fichier résultant.

outre le fait que l’on peut paramétrer tout un tas de valeurs de reglage ( gain, AWB, ISO, résolution, shuter speed, etc …) . il est important de noter qu’avec la librairie PICAMERA la vitesse d’obturation (shutter speed ) est en fait dépendante directement du framerate. il est donc indispensable de ne jamais dissocier les deux => donc on défini systématiquement le framerate avec la fonction Fraction , et ensuite le shutter speed a l’identique avec la même valeur x 1000000.

ATTENTION: si au lancement du programme vous avez un message d’erreur Python du genre « out of ressources error » c’est en général que la memoire graphique GPU allouée est insuffisante . en standard elle est souvent fixée a 128, mais pour du traitement d’image pause longue a la def max du capteur de la PI cam HQ il faut au minimum passer a 256 . pour cela , via le shell aller dans le fichier « boot/config.txt » et avec l’éditeur nano de debian modifier la valeur memoire de 128 a 256 . cela devrait régler le problème. il est egalement possible de modifier l’allocation GPU dans le menu de configuration de la version debian avec bureau et ecran type windows.

NOTE: je n’ai personnellement pas reussi a faire des pauses de plus de 50 secondes avec la librairie PICAMERA , cela semble etre du a une limitation a 60 secondes du parametre time_out dans les fichiers de config et d’erreur de la librairie.

la PI camera HQ est fournie en standard avec un cadre fileté au pas de monture photo Type C . pour l’utiliser sur un telescope ou une lunette , il faut lui adjoindre un adaptateur d’oculaire au pas de la monture type C ( 11€ sur Amazone tarif mai 2021):

sur la base du premier programme , il est facile de programmer une sequence de prise de vues pause longue en automatique en ajoutant une boucle while avec increment et de numeroter automatiquement le nom du fichier a l’enregistrement :


import picamera
from time import sleep
from fractions import Fraction
camera = picamera.PiCamera()
camera.resolution=(4056, 3040)
camera.sensor_mode=3
camera.exposure_mode = 'off'
camera.awb_mode = 'off'
camera.framerate =Fraction(1,50)
camera.shutter_speed = 50000000
camera.iso = 800

i=1
while i=< 5:
	camera.capture('pauselongue' + str(i) +'.jpg')
	sleep(10)
	i=i+1

ce deuxième programme fait donc une série de 5 photos en pause de 50 secondes chacune avec un temps d’attente de 10 secondes entre chaque photo.

sur ces bases et en utilisant Tkinter ( voir rubrique ICI et ICI ) il est possible de faire des menu et d’intégrer des boutons et sliders pour paramétrer le nombre de photos, le temps de pause , le temps interpose , la sensibilité ISO et tous les autres paramètres potentiels utilisables.

exemple d’une appli perso qui transforme la PI cam HQ en capteur multimode combinant Video / timelapse Photo / timelaps pauses longues, l’ensemble très pratique en mode nomade avec un ecran TFT HDMI touschscreen qui permet d’activer les sliders et boutons sans clavier ni souris …

a vos clavier pour développer vos appli perso ….

pour aller plus loin , voici le lien vers la documentation picamera:

https://picamera.readthedocs.io/en/release-1.13/index.html

OpenCV – installation

pour pouvoir utiliser openCV en Python , il faut installer la bibliothèque adéquate. ci dessous la procédure .

première chose a faire vérifier que tout est a la dernière version coté systeme .

donc lancer les classiques commandes shell suivantes:

sudo apt update
sudo apt upgrade

avant de continuer , verifier que python3 est installé. puis pour l’installation d’openCV , pas de grosses difficultés , taper dans le shell la ligne de commande suivante:

sudo apt install python3-opencv

une fois terminé , rebooter votre raspberry Pi.

OpenCV – Images et videos

ouvrir et afficher une image ou le flux d’une camera USB , c’est le thème de ce tuto.

voyons pour commencer comment ouvrir une image enregistrée dans un fichier dans le même répertoire que le pgme python:

import cv2  

# affichage greyscale mode
img0 = cv2.imread('flower.png', 0)
# affichage colormode
img1 = cv2.imread('flower.png', 1)

while True:  
    cv2.imshow('image 0', img0)
    cv2.imshow('image 1', img1)
    if cv2.waitKey(1) == 27:
        break 

cv2.destroyAllWindows()

cela donne le resultat suivant ou nous voyons l’iamge en deux versions, echelle de gris et couleur .

voyons maintenant comment afficher le flux video d’une camera USB avec les memes principes:

explications du programme

import cv2
# connection a la camera
cap = cv2.VideoCapture(0)

while (True):
    # lecture d'une image (frame) du flux video
    ret, frame = cap.read()
    # affichage de l'image (frame) dans une fenetre nommée "Video"
    cv2.imshow('Video', frame)
    # test appui clavier et si touche ESC arret boucle while
    if cv2.waitKey(1) == 27:
        break 
# arret flux camera   
cap.release  
# fermeture des toutes les fenetres d'affichage
cv2.destroyAllWindows()

en resultat , le flux des images s’affiche dans une fenêtre comme ci dessous:

améliorons le programme en ajoutant l’enregistrement du flux vidéo dans un fichier :

import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
videowriter = cv2.VideoWriter("capture.avi", fourcc, 25, (640, 480));

while (True):
    ret, frame = cap.read()
    videowriter.write(frame)
    cv2.imshow('Video', frame)    
    
    if cv2.waitKey(1) == 27:
        break    
 
cap.release()
videowriter.release()  
cv2.destroyAllWindows()

derniere amelio, l’enregistrement du flux video image par image :

import cv2
cap = cv2.VideoCapture(0)

i=1
while (True):
    ret, frame = cap.read()
    cv2.imwrite('captureImg'+str(i)+'.jpg', frame)
    cv2.imshow('Video', frame)
    i+=1    
    
    if cv2.waitKey(1) == 27:
        break    
 
cap.release() 
cv2.destroyAllWindows()

a partir des ces quelques bases il est ensuite possible d’imaginer des développements, par exemple des boutons dans une fenetre Tkinter permettant de déclencher la prise d’une photo ou l’enregistrement vidéo a la demande et non pas en permanence .