<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://wiki-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tbrenier</id>
	<title>wiki-se.plil.fr - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tbrenier"/>
	<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php/Sp%C3%A9cial:Contributions/Tbrenier"/>
	<updated>2026-05-14T21:14:39Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=4003</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=4003"/>
		<updated>2024-01-20T14:43:32Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Utilisation des programmes présentés ci-dessus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Résumé de séance =&lt;br /&gt;
&lt;br /&gt;
=== Séance 1 : ===&lt;br /&gt;
* Création et configuration de la VM sur Chassiron&lt;br /&gt;
* Installation de NanoEdge&lt;br /&gt;
* Installation de STM32cube&lt;br /&gt;
* Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
* Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
* Début de réflexion sur l'application (métrologie)&lt;br /&gt;
&lt;br /&gt;
=== Séance 2: ===&lt;br /&gt;
&lt;br /&gt;
* Mise en place du serveur python&lt;br /&gt;
&lt;br /&gt;
*Mise en place du client python&lt;br /&gt;
*Test réussi de communication entre client et serveur via http&lt;br /&gt;
*Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
*Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
*Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
*Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
*Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
=== Séance 3: ===&lt;br /&gt;
*Entraînement d'un nouveau modèle.&lt;br /&gt;
*Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
&lt;br /&gt;
=== Séance 4 : ===&lt;br /&gt;
*Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
*Amélioration du [[Code de récupération de donnée (sur la raspberry)|programme python]] permettant de récupérer les données du capteur.&lt;br /&gt;
**Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
**Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
*L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
*Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
**Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
= Programmation des interfaces du serveur =&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Code du client Python :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Index permettant d'afficher le json de test que nous avons envoyé au serveur :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :''' ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Flash du capteur sur le logiciel STM32CubeIDE =&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Code de récupération de donnée (sur la raspberry) =&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Utilisation des programmes présentés ci-dessus =&lt;br /&gt;
Nous avons entrainé le programme grâce au logiciel NanoEdge Studio AI, à reconnaitre différentes fournitures scolaires.&lt;br /&gt;
&lt;br /&gt;
Voici ci-dessous un exemple de résultat renvoyés avec aucun objet, une colle et un stabilo.[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]Nous pouvons voir sur la première image que c'est la classe &amp;quot;X&amp;quot; qui est reconnu avec une probabilité de 100%. Sur la seconde image la classe &amp;quot;Colle&amp;quot; est reconnu à 94%. Enfin sur la dernière image la classe &amp;quot;Stabilo&amp;quot; est reconnu à 100%.&lt;br /&gt;
&lt;br /&gt;
A première vue ce sont de bons résultats, cependant ils sont obtenus dans des conditions d'expérimentation fixe, le capteur est toujours à la même distance de la table. Les résultats chutes drastiquement si l'on change la position du capteur. Il faudrait donc entraîner d'avantage le programme dans d'autres conditions afin qu'il soit plus performant.&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=4002</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=4002"/>
		<updated>2024-01-20T14:23:45Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Code du client Python : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Résumé de séance =&lt;br /&gt;
&lt;br /&gt;
=== Séance 1 : ===&lt;br /&gt;
* Création et configuration de la VM sur Chassiron&lt;br /&gt;
* Installation de NanoEdge&lt;br /&gt;
* Installation de STM32cube&lt;br /&gt;
* Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
* Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
* Début de réflexion sur l'application (métrologie)&lt;br /&gt;
&lt;br /&gt;
=== Séance 2: ===&lt;br /&gt;
&lt;br /&gt;
* Mise en place du serveur python&lt;br /&gt;
&lt;br /&gt;
*Mise en place du client python&lt;br /&gt;
*Test réussi de communication entre client et serveur via http&lt;br /&gt;
*Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
*Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
*Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
*Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
*Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
=== Séance 3: ===&lt;br /&gt;
*Entraînement d'un nouveau modèle.&lt;br /&gt;
*Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
&lt;br /&gt;
=== Séance 4 : ===&lt;br /&gt;
*Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
*Amélioration du [[Code de récupération de donnée (sur la raspberry)|programme python]] permettant de récupérer les données du capteur.&lt;br /&gt;
**Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
**Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
*L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
*Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
**Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
= Programmation des interfaces du serveur =&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Code du client Python :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Index permettant d'afficher le json de test que nous avons envoyé au serveur :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :''' ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Flash du capteur sur le logiciel STM32CubeIDE =&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Code de récupération de donnée (sur la raspberry) =&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Utilisation des programmes présentés ci-dessus =&lt;br /&gt;
Nous avons entrainé le programme grâce au logiciel NanoEdge Studio AI, à reconnaitre différentes fournitures scolaires.&lt;br /&gt;
&lt;br /&gt;
Voici ci-dessous un exemple avec aucun objet, une colle et un stabilo.[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]Nous po&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=4000</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=4000"/>
		<updated>2024-01-20T14:18:59Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Utilisation des programmes présentés ci-dessus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Résumé de séance =&lt;br /&gt;
* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du [[Code de récupération de donnée (sur la raspberry)|programme python]] permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Code du client Python :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Index permettant d'afficher le json de test que nous avons envoyé au serveur :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :''' ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Flash du capteur sur le logiciel STM32CubeIDE =&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Code de récupération de donnée (sur la raspberry) =&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Utilisation des programmes présentés ci-dessus =&lt;br /&gt;
Nous avons entrainé le programme pour reconnaitre[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3999</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3999"/>
		<updated>2024-01-20T14:13:03Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Code de récupération de donnée (sur la raspberry) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Résumé de séance =&lt;br /&gt;
* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du [[Code de récupération de donnée (sur la raspberry)|programme python]] permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Code du client Python :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Index permettant d'afficher le json de test que nous avons envoyé au serveur :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :''' ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Flash du capteur sur le logiciel STM32CubeIDE =&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Code de récupération de donnée (sur la raspberry) =&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Utilisation des programmes présentés ci-dessus =&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3998</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3998"/>
		<updated>2024-01-20T14:12:28Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Utilisation des programmes présentés ci-dessus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Résumé de séance =&lt;br /&gt;
* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du [[Code de récupération de donnée (sur la raspberry)|programme python]] permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Code du client Python :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Index permettant d'afficher le json de test que nous avons envoyé au serveur :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :''' ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Flash du capteur sur le logiciel STM32CubeIDE =&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Code de récupération de donnée (sur la raspberry) =&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Utilisation des programmes présentés ci-dessus ==&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3997</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3997"/>
		<updated>2024-01-20T14:11:58Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Utilisation des programmes présentés ci-dessus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Résumé de séance =&lt;br /&gt;
* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du [[Code de récupération de donnée (sur la raspberry)|programme python]] permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Code du client Python :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Index permettant d'afficher le json de test que nous avons envoyé au serveur :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :''' ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Flash du capteur sur le logiciel STM32CubeIDE =&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Code de récupération de donnée (sur la raspberry) =&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Utilisation des programmes présentés ci-dessus ===&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3996</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3996"/>
		<updated>2024-01-20T14:11:18Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Résumé de séance =&lt;br /&gt;
* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du [[Code de récupération de donnée (sur la raspberry)|programme python]] permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt; ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Code du client Python :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Index permettant d'afficher le json de test que nous avons envoyé au serveur :''' ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== '''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :''' ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Flash du capteur sur le logiciel STM32CubeIDE =&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Code de récupération de donnée (sur la raspberry) =&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Utilisation des programmes présentés ci-dessus =&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3992</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3992"/>
		<updated>2024-01-20T13:58:31Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173812.jpg|vignette|Un stabilo à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:20231220_173812.jpg&amp;diff=3991</id>
		<title>Fichier:20231220 173812.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:20231220_173812.jpg&amp;diff=3991"/>
		<updated>2024-01-20T13:57:51Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Un stabilo à reconnaitre&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3990</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3990"/>
		<updated>2024-01-20T13:56:20Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|centre|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3989</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3989"/>
		<updated>2024-01-20T13:56:03Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
# Événement pour signaler l'arrêt des threads&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
# Fonction de thread pour lire les données et les sauvegarder dans des fichiers&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    # Chemin du fichier pour les données initiales du capteur&lt;br /&gt;
    # Ces données sont vouées à ne pas être utilisées&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        # Créer un nouveau fichier pour chaque minute avec l'horodatage actuel&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Fermer le fichier de la minute précédente en ajoutant la parenthèse fermante&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Lire les données du port série&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        # Ouvrir le fichier de la minute actuelle et écrire les données&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            # S'il s'agit d'une nouvelle minute, commencer un nouvel objet JSON&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            # Écrire les données dans le fichier&lt;br /&gt;
            fichier.write(string)&lt;br /&gt;
&lt;br /&gt;
# Gestionnaire de signal pour définir l'événement d'interruption lors d'une interruption clavier (Ctrl+C)&lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
# Fonction principale&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    # Créer un objet pour la communication série&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
&lt;br /&gt;
    # Créer un thread pour la communication série&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    # Démarrer le thread de communication série&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    # Mettre en place le gestionnaire de signal pour les événements d'interruption (Ctrl+C)&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)&lt;br /&gt;
&lt;br /&gt;
    # Attendre pendant 5 secondes et supprimer le fichier de données initial du capteur&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        # Vérifier si l'événement d'interruption est défini&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            # Attendre que le thread série se termine, puis sortir de la boucle&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        # Ajuster les valeurs de minute et d'heure pour l'heure précédente&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
&lt;br /&gt;
        # On modifie tout les \n du fichier json afin que son transfert et sa réception vers le serveur&lt;br /&gt;
        # soit du bon format. On protège donc tout les \n du fichier avant son envoie.&lt;br /&gt;
        try:&lt;br /&gt;
            # Lire et modifier le contenu du fichier de la minute précédente&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de chemins de fichiers pour les 10 dernières minutes&lt;br /&gt;
        # Tout les autres sont amenés à être supprimés. Dans le but de préserver de la mémoire de stockage&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        # Obtenir une liste de tous les fichiers dans le répertoire data&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Créer une liste de fichiers à supprimer&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        # Vérifier chaque fichier et l'ajouter à la liste de suppression s'il n'est pas dans la liste des fichiers à conserver&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        # Supprimer les fichiers de la liste de suppression&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
# Point d'entrée du script&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173733.jpg|gauche|vignette|Une colle à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3987</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3987"/>
		<updated>2024-01-20T13:55:35Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;br /&gt;
[[Fichier:20231220 173733.jpg|vignette|Une colle à reconnaitre]]&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:20231220_173733.jpg&amp;diff=3986</id>
		<title>Fichier:20231220 173733.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:20231220_173733.jpg&amp;diff=3986"/>
		<updated>2024-01-20T13:55:03Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Une colle à reconnaitre&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3985</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3985"/>
		<updated>2024-01-20T13:53:10Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;br /&gt;
[[Fichier:20231220 173650.jpg|gauche|vignette|Aucun objet à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3984</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3984"/>
		<updated>2024-01-20T13:52:05Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;br /&gt;
[[Fichier:20231220 173650.jpg|centre|Aucun objet à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3983</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3983"/>
		<updated>2024-01-20T13:51:23Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Résultats renvoyés par le programme de reconnaissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;br /&gt;
[[Fichier:20231220 173650.jpg|vignette|Aucun objet à reconnaitre]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:20231220_173650.jpg&amp;diff=3982</id>
		<title>Fichier:20231220 173650.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:20231220_173650.jpg&amp;diff=3982"/>
		<updated>2024-01-20T13:50:43Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Aucun objet à reconnaitre&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3981</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3981"/>
		<updated>2024-01-20T13:43:59Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Code de récupération de donnée (sur la raspberry) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Résultats renvoyés par le programme de reconnaissance ==&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3980</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3980"/>
		<updated>2024-01-20T13:41:56Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Flash du capteur sur le logiciel STM32CubeIDE */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|centre|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3979</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3979"/>
		<updated>2024-01-20T13:38:35Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|vignette|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3978</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3978"/>
		<updated>2024-01-20T13:36:44Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|vignette|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
== Flash du capteur sur le logiciel STM32CubeIDE ==&lt;br /&gt;
Le code ci-dessous est la fonction qui est appelé pour le traitement des capteurs. Nous avions décidé de définir le délimiteur de donnée avec un espace.&lt;br /&gt;
&lt;br /&gt;
Ci-dessous, on retrouve de la ligne 8 à 12 la configuration du capteur que l'on a défini sur un quadrillage de 8 x 8.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
static void MX_53L5A1_SimpleRanging_Process(void)&lt;br /&gt;
{&lt;br /&gt;
  uint32_t Id;&lt;br /&gt;
&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ReadID(VL53L5A1_DEV_CENTER, &amp;amp;Id);&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_GetCapabilities(VL53L5A1_DEV_CENTER, &amp;amp;Cap);&lt;br /&gt;
&lt;br /&gt;
  Profile.RangingProfile = RS_PROFILE_8x8_CONTINUOUS;&lt;br /&gt;
  Profile.TimingBudget = TIMING_BUDGET; /* 5 ms &amp;lt; TimingBudget &amp;lt; 100 ms */&lt;br /&gt;
  Profile.Frequency = RANGING_FREQUENCY; /* Ranging frequency Hz (shall be consistent with TimingBudget value) */&lt;br /&gt;
  Profile.EnableAmbient = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
  Profile.EnableSignal = 0; /* Enable: 1, Disable: 0 */&lt;br /&gt;
&lt;br /&gt;
  /* set the profile if different from default one */&lt;br /&gt;
  VL53L5A1_RANGING_SENSOR_ConfigProfile(VL53L5A1_DEV_CENTER, &amp;amp;Profile);&lt;br /&gt;
&lt;br /&gt;
  status = VL53L5A1_RANGING_SENSOR_Start(VL53L5A1_DEV_CENTER, RS_MODE_BLOCKING_CONTINUOUS);&lt;br /&gt;
&lt;br /&gt;
  if (status != BSP_ERROR_NONE)&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;VL53L5A1_RANGING_SENSOR_Start failed\n&amp;quot;);&lt;br /&gt;
    while (1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    /* polling mode */&lt;br /&gt;
    status = VL53L5A1_RANGING_SENSOR_GetDistance(VL53L5A1_DEV_CENTER, &amp;amp;Result);&lt;br /&gt;
&lt;br /&gt;
    if (status == BSP_ERROR_NONE)&lt;br /&gt;
    {&lt;br /&gt;
      //print_result(&amp;amp;Result);&lt;br /&gt;
      print_result_IE(&amp;amp;Result);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (com_has_data())&lt;br /&gt;
    {&lt;br /&gt;
      handle_cmd(get_key());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    HAL_Delay(POLLING_PERIOD);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le code ci-dessous est la fonction qui nous permet d'afficher les données des capteurs via la liaison série.&lt;br /&gt;
&lt;br /&gt;
On observe l'envoie des données avec un séparateur 'espace', puis lorsque les valeurs semblent incohérentes du point de vue du capteur, on envoie arbitrairement un -1 en sortie.&lt;br /&gt;
&lt;br /&gt;
On obtient un jeu de donnée suivant le format : value espace value esapce .... value espace retour chariot   (pour chaque lignes/quadrillage sur une ligne)&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static void print_result_IE(RANGING_SENSOR_Result_t *Result)&lt;br /&gt;
{&lt;br /&gt;
  int8_t j;&lt;br /&gt;
  int8_t k;&lt;br /&gt;
  int8_t l;&lt;br /&gt;
  uint8_t zones_per_line;&lt;br /&gt;
&lt;br /&gt;
  zones_per_line = ((Profile.RangingProfile == RS_PROFILE_8x8_AUTONOMOUS) ||&lt;br /&gt;
		 (Profile.RangingProfile == RS_PROFILE_8x8_CONTINUOUS)) ? 8 : 4;&lt;br /&gt;
&lt;br /&gt;
  for (j = 0; j &amp;lt; Result-&amp;gt;NumberOfZones; j += zones_per_line)&lt;br /&gt;
  {&lt;br /&gt;
	for (l = 0; l &amp;lt; RANGING_SENSOR_NB_TARGET_PER_ZONE; l++)&lt;br /&gt;
	{&lt;br /&gt;
	  /* Print distance and status */&lt;br /&gt;
	  for (k = (zones_per_line - 1); k &amp;gt;= 0; k--)&lt;br /&gt;
	  {&lt;br /&gt;
		if (Result-&amp;gt;ZoneResult[j+k].NumberOfTargets &amp;gt; 0)&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;,(long)Result-&amp;gt;ZoneResult[j+k].Distance[l]);&lt;br /&gt;
		else&lt;br /&gt;
		  printf(&amp;quot;%ld &amp;quot;, -1);&lt;br /&gt;
	  }&lt;br /&gt;
	}&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formater dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
import serial&lt;br /&gt;
from threading import Thread, Event&lt;br /&gt;
from time import sleep&lt;br /&gt;
import os, sys, signal&lt;br /&gt;
import datetime&lt;br /&gt;
import glob&lt;br /&gt;
&lt;br /&gt;
interruptAllEvent = Event()&lt;br /&gt;
&lt;br /&gt;
def serial_thread(ser: serial) -&amp;gt; None:&lt;br /&gt;
    fileName_old = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;&lt;br /&gt;
    while (1):&lt;br /&gt;
        if (interruptAllEvent.is_set()):&lt;br /&gt;
            break&lt;br /&gt;
        fileName = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__%H_%M_00&amp;quot;) + &amp;quot;.json&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if (fileName_old != fileName):&lt;br /&gt;
            with open(fileName_old, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
                fichier.write(&amp;quot;\&amp;quot;}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        string = str(ser.readline(), encoding='utf-8')&lt;br /&gt;
&lt;br /&gt;
        with open(fileName, &amp;quot;a&amp;quot;) as fichier:&lt;br /&gt;
            if (fileName_old != fileName):&lt;br /&gt;
                fileName_old = fileName&lt;br /&gt;
                fichier.write(&amp;quot;{\&amp;quot;date\&amp;quot;:\&amp;quot;&amp;quot;+datetime.datetime.now().strftime(&amp;quot;%d/%m/%Y-%H:%M:00&amp;quot;)+&amp;quot;\&amp;quot;,\&amp;quot;csv_file\&amp;quot;:\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            fichier.write(string)        &lt;br /&gt;
        &lt;br /&gt;
def signal_handler(sig, frame):&lt;br /&gt;
    interruptAllEvent.set()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; None:&lt;br /&gt;
    ser = serial.Serial('/dev/ttyACM0', 460800)&lt;br /&gt;
    thread = Thread(target=serial_thread, args=(ser,))&lt;br /&gt;
&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
    signal.signal(signal.SIGINT, signal_handler)   &lt;br /&gt;
&lt;br /&gt;
    sleep(5)&lt;br /&gt;
    os.remove(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_start&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    while (1):&lt;br /&gt;
        if interruptAllEvent.is_set():&lt;br /&gt;
            thread.join()&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        sleep(5)&lt;br /&gt;
&lt;br /&gt;
        minute = datetime.datetime.now().minute - 1&lt;br /&gt;
        hours = datetime.datetime.now().hour&lt;br /&gt;
        if (minute &amp;lt; 0):&lt;br /&gt;
            minute = minute + 60&lt;br /&gt;
            hours = hours - 1&lt;br /&gt;
        try:&lt;br /&gt;
            with open(os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;, &amp;quot;r+&amp;quot;) as fichier:&lt;br /&gt;
                line = fichier.read()&lt;br /&gt;
                str(line).replace('\n','\\\n')&lt;br /&gt;
                fichier.write(line)&lt;br /&gt;
        except FileNotFoundError:&lt;br /&gt;
            sleep(60)&lt;br /&gt;
&lt;br /&gt;
        file_to_keep = []&lt;br /&gt;
        for i in range(0,10):&lt;br /&gt;
            minute = datetime.datetime.now().minute - i&lt;br /&gt;
            hours = datetime.datetime.now().hour&lt;br /&gt;
            if (minute &amp;lt; 0):&lt;br /&gt;
                minute = minute + 60&lt;br /&gt;
                hours = hours - 1&lt;br /&gt;
            path_string = os.path.dirname(__file__) + &amp;quot;/data/sensor_data_&amp;quot; + datetime.datetime.now().strftime(&amp;quot;%d_%m_%Y__&amp;quot;) + str(hours) + &amp;quot;_&amp;quot; + str(minute) + &amp;quot;_00.json&amp;quot;&lt;br /&gt;
            file_to_keep.append(path_string)&lt;br /&gt;
&lt;br /&gt;
        files = glob.glob(os.path.dirname(__file__) + &amp;quot;/data/*&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        files_to_remove = []&lt;br /&gt;
&lt;br /&gt;
        for file_name in files:&lt;br /&gt;
            beRemoved = True&lt;br /&gt;
            for f_keep in file_to_keep:&lt;br /&gt;
                if file_name == f_keep:&lt;br /&gt;
                    beRemoved = False&lt;br /&gt;
                    break&lt;br /&gt;
            if beRemoved:&lt;br /&gt;
                files_to_remove.append(file_name)&lt;br /&gt;
&lt;br /&gt;
        for file_name in files_to_remove:&lt;br /&gt;
            os.remove(file_name)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
        main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3861</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3861"/>
		<updated>2024-01-16T16:19:50Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de clef WEP d'un point d'accès WiFi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
Voir détails sur : [[Atelier SysRes SE5 2023/2024 E6|Cahier n°6]]     [[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
Voir détails sur : [[Atelier SysRes SE5 2023/2024 E6|Cahier n°6]] &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3860</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3860"/>
		<updated>2024-01-16T16:17:09Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de clef WEP d'un point d'accès WiFi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
Voir détails sur :     [[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
Voir détails sur : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3859</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3859"/>
		<updated>2024-01-16T16:16:51Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de clef WEP d'un point d'accès WiFi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
Voir détails sur :    [[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
Voir détails sur : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3857</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3857"/>
		<updated>2024-01-16T16:16:08Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de clef WEP d'un point d'accès WiFi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
Voir détails sur : [[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
Voir détails sur : &lt;br /&gt;
&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3856</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3856"/>
		<updated>2024-01-16T16:15:17Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de clef WEP d'un point d'accès WiFi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
Voir détails sur : [[Atelier SysRes SE5 2023/2024 E7 |Cahier n°7]][[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
Voir détails sur : [[Atelier SysRes SE5 2023/2024 E7 |Cahier n°7]]&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3854</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3854"/>
		<updated>2024-01-16T16:13:27Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de mot de passe WPA-PSK par force brute */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
Voir détails sur :[[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
Voir détails sur :&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3853</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3853"/>
		<updated>2024-01-16T16:13:10Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de clef WEP d'un point d'accès WiFi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
Voir détails sur :[[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3852</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3852"/>
		<updated>2024-01-16T16:12:44Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de mot de passe WPA-PSK par force brute */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
[[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;br /&gt;
[[Fichier:Crack wifi wpa.png|sans_cadre|762x762px]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3851</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3851"/>
		<updated>2024-01-16T16:12:33Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Cassage de clef WEP d'un point d'accès WiFi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
[[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;br /&gt;
&lt;br /&gt;
=== Cassage de mot de passe WPA-PSK par force brute ===&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3850</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3850"/>
		<updated>2024-01-16T16:10:44Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Cassage de clef WEP d'un point d'accès WiFi ===&lt;br /&gt;
[[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3849</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3849"/>
		<updated>2024-01-16T16:09:55Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Crack clef WEP.png|vignette|1561x1561px|néant]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3838</id>
		<title>Atelier SysRes SE5 2023/2024 E7</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E7&amp;diff=3838"/>
		<updated>2024-01-16T15:52:10Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : Page vide créée&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E6&amp;diff=3837</id>
		<title>Atelier SysRes SE5 2023/2024 E6</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Atelier_SysRes_SE5_2023/2024_E6&amp;diff=3837"/>
		<updated>2024-01-16T15:51:56Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : Page vide créée&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=3765</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=3765"/>
		<updated>2024-01-15T07:03:21Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : /* Répartition des binômes en PRA */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui Mohammed&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Blgrim Haitam&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Konstantin PATRIKEEV&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Karl HABRE&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Rémi FARAULT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en PRA ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| Elom|| || || Baloo|| || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| Mustafar (Mustafare)|| || mustafare.lol|| Baloo|| 193.48.57.189|| Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| Dagobah|| || dagobah.lol|| Aladin|| || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| Motis|| || || Dingo|| || Mohammed Halaoui&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| bogano|| || || Timon|| || Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| Takobo|| || &amp;lt;code&amp;gt;takobo.lol&amp;lt;/code&amp;gt;|| Timon|| 193.48.57.184|| Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| Fondor|| || || mushu|| 193.48.57.190|| Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| hoth|| || || BlancheNeige|| 193.48.57.187|| Haitam Blgrim&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| Abafar|| || abafar.lol|| Aladin|| 193.48.57.179|| Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| Rotia|| || || DIngo|| 193.48.57.181|| Rémi Farault&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| jedha|| || || judy|| 193.48.57.182|| Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| Bogden|| || || BlancheNeige|| || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| endor|| 10.10.10.10|| || mickey|| 193.48.57.188 / 10.10.10.1|| Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| jiruus|| 192.168.19.3|| jiruus.lol|| cruella|| || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| exegol|| 192.168.19.2|| exegol.lol|| cruella|| 193.48.57.186 /&lt;br /&gt;
192.168.19.1&lt;br /&gt;
| Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| Jakku|| || || Jafar|| || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| naboo|| 192.168.18.2|| naboo.lol|| bouh|| 193.48.57.180 / 192.168.18.1|| Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| geonosis|| 192.168.18.3|| geonosis.lol|| bouh|| || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| alderaan|| || || Jafar|| 193.48.57.183|| Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| kesh|| || || Judy|| || Konstantin Patrikeev&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| kashyyyk|| || || mushu|| || Maxime BALBASTRE&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| Felucia|| 192.168.26.2|| || Ursula|| 193.48.57.185 / 192.168.26.1|| François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| Pelagon|| 10.10.10.11|| || mickey|| 193.48.57.188 / 10.10.10.1|| Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
|[[Atelier SysRes SE5 2023/2024 E24 | Cahier n°25]]&lt;br /&gt;
|Kalee&lt;br /&gt;
|192.168.26.3&lt;br /&gt;
|kalee.lol&lt;br /&gt;
|Ursula&lt;br /&gt;
|&lt;br /&gt;
|Karl Habre&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 20/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
A noter qu'aucune machine, quelle soit de service ou mandataire, ne peut avoir accès à Internet vu qu'aucun effort n'a été fait pour relier le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; au réseau SE5.&lt;br /&gt;
&lt;br /&gt;
Machines de service.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE || Ursula|| rien&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Liste des machines&lt;br /&gt;
&lt;br /&gt;
 Elom Mustafar dagobah Motis bogano Takobo Fondor hoth abafar Rotia jedha Bogden jiruus exegol Jakku naboo geonosis alderaan kesh kashyyyk Felucia&lt;br /&gt;
&lt;br /&gt;
 Baloo aladin Dingo Timon mushu BlancheNeige cruella Jafar bouh judy&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 03/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; a été relié au réseau SE5 par &amp;lt;code&amp;gt;naboo&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Il est normal de ne pas avoir d'adresse IPv4 sur la machine de services pour l'interface sur le commutateur virtuel. Par contre, avec mise en place de la mascarade sur la machine mandataire, il doit être possible, pour la machine de services, de se connecter à Internet en IPv4.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON&lt;br /&gt;
| IPv4 sur CV : 10.0.69.220, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0f:b26d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fea9:f79, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG&lt;br /&gt;
| IPv4 sur CV : 10.0.69.205, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe53:7d33, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui&lt;br /&gt;
| IPv4 sur CV : 10.0.69.195, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7c:2d6a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen&lt;br /&gt;
| IPv4 sur CV : 10.0.69.245, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe62:6960, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier&lt;br /&gt;
| IPv4 sur CV : 10.0.69.181, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe93:8c48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée&lt;br /&gt;
| IPv4 sur CV : 10.0.69.200, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2d:82bf, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim&lt;br /&gt;
| IPv4 sur CV : 10.0.69.157, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee8:4736, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI&lt;br /&gt;
| IPv4 sur CV : 10.0.69.233, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feae:bcbb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2e:ec48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.221, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef6:364f, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste&lt;br /&gt;
| IPv4 sur CV : 10.0.69.246, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe67:89fd, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.247, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe9c:6f0e, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard&lt;br /&gt;
| IPv4 sur CV : 10.0.69.147, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe17:bc38, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY&lt;br /&gt;
| IPv4 sur CV : 10.0.69.136, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee1:1e4d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire&lt;br /&gt;
| IPv4 sur CV : 192.168.18.2, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef2:7e2, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS&lt;br /&gt;
| IPv4 sur CV : 10.0.69.231, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feb0:b140, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON&lt;br /&gt;
| IPv4 sur CV : 10.0.69.106, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe97:2114, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev&lt;br /&gt;
| IPv4 sur CV : 10.0.69.222, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe10:e2cb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE&lt;br /&gt;
| IPv4 sur CV : 10.0.69.240, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feca:73e7, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT&lt;br /&gt;
| IPv4 sur CV : 10.0.69.139, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe89:460a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo &lt;br /&gt;
| IPv4 sur CV : 10.0.69.152, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fec8:5379, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin&lt;br /&gt;
| IPv4 sur CV : 10.0.69.107, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe6b:c000, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo&lt;br /&gt;
| IPv4 sur CV : 10.0.69.156, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0d:4f9c, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon&lt;br /&gt;
| IPv4 sur CV : 10.0.69.104, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fedc:7539, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu&lt;br /&gt;
| IPv4 sur CV : 10.0.69.160, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe20:8816, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige&lt;br /&gt;
| IPv4 sur CV : 10.0.69.182, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feba:38f4, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella&lt;br /&gt;
| IPv4 sur CV : 10.0.69.108, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee5:ff99, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar&lt;br /&gt;
| IPv4 sur CV : 10.0.69.171, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe3e:f0bb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh&lt;br /&gt;
| IPv4 sur CV : 192.168.18.1, IPv4 sur SE5 : 193.48.57.180, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe4f:dde2, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy&lt;br /&gt;
| IPv4 sur CV : 10.0.69.216, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7d:4762, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 11/01/2024 ===&lt;br /&gt;
&lt;br /&gt;
Il est normal de ne pas avoir d'adresse IPv4 sur la machine de services pour l'interface sur le commutateur virtuel. Par contre, avec mise en place de la mascarade sur la machine mandataire, il doit être possible, pour la machine de services, de se connecter à Internet en IPv4.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Interfaces dans SE5 et CV !! Domaine Internet !! Accès &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; root !! DNS installé&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;elom.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;mustafare.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;dagobah.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;motis.hair&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;bogano.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;takobo.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;fondor.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;hoth.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;abafar.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault&lt;br /&gt;
| SE5 uniquement || Aucun&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux&lt;br /&gt;
| SE5 uniquement || Aucun&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;bodgen.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;jiruus.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;exegol.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;jakku.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;naboo.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;geonosis.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;alderaan.website&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;kesh.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;kashyyyk.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT&lt;br /&gt;
| SE5 uniquement || &amp;lt;code&amp;gt;felucia.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| pelagon || Paul AMOROS&lt;br /&gt;
| activée le 11/01/2024 (IPv6 &amp;lt;code&amp;gt;2001:660:4401:60b0:216:3eff:fe03:2af3&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;pelagon.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Kalee || Karl HABRE&lt;br /&gt;
| pas de machine virtuelle || &amp;lt;code&amp;gt;kalee.lol&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Commutateur virtuel !! Interfaces dans SE5 et CV !! Accès &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; root !! DNS installé&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo &lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh&lt;br /&gt;
| Oui || Oui&lt;br /&gt;
| Ajouté || Non&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy&lt;br /&gt;
| Non || Non&lt;br /&gt;
| Non || Non&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE || Ursula&lt;br /&gt;
| || &lt;br /&gt;
| || &lt;br /&gt;
|-&lt;br /&gt;
| Paul AMOROS || mandataire inconnu&lt;br /&gt;
| || &lt;br /&gt;
| || &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 14/01/2024 ===&lt;br /&gt;
&lt;br /&gt;
Il est normal, pour les machines de services, de ne pas avoir d'@IPv4 sur le commutateur virtuel.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0f:b26d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fea9:f79, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe53:7d33, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7c:2d6a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe62:6960, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe93:8c48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2d:82bf, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim&lt;br /&gt;
| IPv4 sur CV : 10.0.69.157, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee8:4736, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, &amp;lt;code&amp;gt;bind9&amp;lt;/code&amp;gt; installé pas plus.&lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feae:bcbb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2e:ec48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef6:364f, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste&lt;br /&gt;
| IPv4 sur CV : 10.0.69.246, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe67:89fd, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 192.168.19.3, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe9c:6f0e, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard&lt;br /&gt;
| IPv4 sur CV : 192.168.19.2, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe17:bc38, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY&lt;br /&gt;
| IPv4 sur CV : 10.0.69.136, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee1:1e4d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire&lt;br /&gt;
| IPv4 sur CV : 192.168.18.2, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef2:7e2, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel.&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS&lt;br /&gt;
| IPv4 sur CV : 192.168.18.3, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feb0:b140, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, serveur DNS fonctionnel (aide massive).&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe97:2114, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe10:e2cb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feca:73e7, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe89:460a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| pelagon || Paul Amoros&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe03:2af3, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| endor || Maël Delaby&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe5f:ebac, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS fonctionnel (mauvais domaine).&lt;br /&gt;
|-&lt;br /&gt;
| Kalee || Karl Harbre&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe45:42ed, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo &lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fec8:5379, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe6b:c000, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo&lt;br /&gt;
| IPv4 sur CV : 193.48.57.181 10.0.69.156, IPv4 sur SE5 : 193.48.57.181, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0d:4f9c, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fedc:7539, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe20:8816, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.pas de serveur DNS.z&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige&lt;br /&gt;
| IPv4 sur CV : 193.48.57.187 10.0.69.182, IPv4 sur SE5 : 193.48.57.187, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feba:38f4, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, &amp;lt;code&amp;gt;bind9&amp;lt;/code&amp;gt; installé sans plus.&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella&lt;br /&gt;
| IPv4 sur CV : 193.48.57.186 192.168.19.1, IPv4 sur SE5 : 193.48.57.186, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee5:ff99, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS secondaire configuré.&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar&lt;br /&gt;
| IPv4 sur CV : 193.48.57.183 10.0.69.1, IPv4 sur SE5 : 193.48.57.183, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe3e:f0bb, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, &amp;lt;code&amp;gt;bind9&amp;lt;/code&amp;gt; installé sans plus.&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh&lt;br /&gt;
| IPv4 sur CV : 193.48.57.180 192.168.18.1, IPv4 sur SE5 : 193.48.57.180, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe4f:dde2, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS secondaire configuré.&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy&lt;br /&gt;
| IPv4 sur CV : 193.48.57.182, IPv4 sur SE5 : 193.48.57.182, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7d:4762, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
| Paul Amoros &amp;amp; Maël Delaby || mickey&lt;br /&gt;
| IPv4 sur CV : 193.48.57.188 10.10.10.2 10.10.10.1, IPv4 sur SE5 : 193.48.57.188, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe34:13d5, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle, serveur DNS secondaire configuré mais le répertoire pour les zones secondaires n'existe pas, l'écriture échoue.&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT &amp;amp; Karl HABRE || Ursula&lt;br /&gt;
| pas d'IPv4 sur le CV, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe33:7f89, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle, pas de serveur DNS.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en ASR ==&lt;br /&gt;
&lt;br /&gt;
Donnez les élèves dans chaque groupe.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves &lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux &lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros &lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton &lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut &lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali &lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault &lt;br /&gt;
|-&lt;br /&gt;
|g13&lt;br /&gt;
|Maxime Balbastre &amp;amp; Florian Vallée&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Le 05/11/2023, aucun commutateur virtuel correctement configuré, soit une adresse IPv4 sur le commutateur pour aucune raison, soit une configuration &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt; non adaptée, pas de &amp;lt;code&amp;gt;up&amp;lt;/code&amp;gt; sur le commutateur virtuel.&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 05/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Migration !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || || jcharleu, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || kpatrikee, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || || gthomas, CV conf. erronée, MV mdp erroné, interf. vlan50 || clemair1, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, une seule interface réseau, pas de config. réseau&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || || bnguyen1, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || tbrenier, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || || drodenbu, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || fnaudot, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || || pas de CV, pas de MV || mdelaby, CV conf. erronée, pygrub dans la MV ? pas de routeur, faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || || hblgrim, CV conf. erronée, MV avec 2 interfaces, pas de MAC sur la 1ère, config. IPv4 OK || bblack, CV commenté, pas de MV (plus exactement une machine visible via &amp;lt;code&amp;gt;xen list&amp;lt;/code&amp;gt; mais pas de &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;/etc/xen&amp;lt;/code&amp;gt;), pas de routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || || jdelanno, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || amouton, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, une seule interface réseau&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || || mriffaut, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || esimon, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, pas de routeur&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || || jdelcour, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || egodard, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, deux interfaces réseau, changez l'ordre des interfaces dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || || khabre, CV conf. erronée, MV non créée, MV interf. vlan50, pas de config. IPv4 || asellali, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || || rfarault, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || pas de CV, MV interf. vlan50, pas de config. IPv4, pas de routeur&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 20/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
A noter qu'un sacré coup de pouce aura été nécessaire pour configurer le routeur de promotion, avec un seul élève en appui.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Migration !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || || jcharleu, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || kpatrikee, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || || gthomas, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || clemair1, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4, routeur lancé et correctement configuré&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || || bnguyen1, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || tbrenier, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || || drodenbu, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || fnaudot, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || || toujours pas de CV, pas de VLAN, toujours pas de MV || mdelaby, CV configuration toujours erronée, pas de VLAN, toujours le bootloader &amp;lt;code&amp;gt;pygrub&amp;lt;/code&amp;gt; dans la MV (commenté), MV avec une seule interface réseau (dans le CV), configuration DHCP OK pour l'interface (dans le CV), toujours pas de routeur : il faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || || hblgrim, CV conf. toujours erronée, pas de VLAN, MV ne démarre pas à cause de l'erreur sur le CV (correction ReX sur le CV), MV avec 2 interfaces, pas de MAC sur la première interface dans le .cfg, configuration IPv4 OK dans la MV || bblack, CV configuration toujours erronée, pas de VLAN, toujours pas e &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; pour la MV, un routeur OpenWRT avec la bonne définition de disque, deux interface mais sans @MAC, aucune configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || || jdelanno, CV conf. toujours, erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || amouton, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, une seule interface réseau, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || || mriffaut, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || esimon, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || || jdelcour, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || egodard, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, deux interfaces réseau, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || || khabre, CV conf. toujours erronée, pas de VLAN, MV enfin créée avec une seule interface, pas de configuration IPv4 correcte || asellali, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, une seule interface, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || || rfarault, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || pas de CV, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 30/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || jcharleu, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || kpatrikee, CV et VLAN configurés mais dites moi comment vous trouvez 1 avec la formule &amp;lt;code&amp;gt;6+N%4&amp;lt;/code&amp;gt;, MV avec les bonnes interfaces, inversion dans la configuration IPv4 entre &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;enX1&amp;lt;/code&amp;gt;, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; par contre les deux interfaces demandées sont présentes.&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || gthomas, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4. || clemair1, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4, routeur lancé et correctement configuré.&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || bnguyen1, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || tbrenier, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant.&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || drodenbu, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || fnaudot, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant.&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || toujours pas de CV, pas de VLAN, toujours pas de MV. || mdelaby, CV configuration toujours erronée, pas de VLAN, toujours le bootloader &amp;lt;code&amp;gt;pygrub&amp;lt;/code&amp;gt; dans la MV (commenté), MV avec un chemin des disques étranges, MV avec une seule interface réseau (dans le CV), configuration DHCP OK pour l'interface (dans le CV), toujours pas de routeur : il faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || hblgrim, il manque les directives pour démarrer et arrêter les interfaces mais sinon CV et VLAN configurés, MV lancé et configurée, il ne faut pas de &amp;lt;code&amp;gt;gateway&amp;lt;/code&amp;gt; sur &amp;lt;code&amp;gt;enX1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son adresse par DHCP à cause du commutateur virtuel non activé. || bblack, CV et VLAN configurés mais pas toutes les directives de démarrage et d'arrêt, toujours pas de &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; pour la MV, un routeur OpenWRT avec la bonne définition de disque, deux interface mais sans @MAC, aucune configuration du routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || jdelanno, CV conf. toujours, erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte; || amouton, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, une seule interface réseau, pas de configuration du routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || mriffaut, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte. || esimon, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || jdelcour, CV configuré, VLAN configuré (par contre l'utilisation de &amp;lt;code&amp;gt;ether4&amp;lt;/code&amp;gt; est impossible), MV lancée et correctement configurée en IPv4, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son @IPv4 à cause de l'erreur sur le VLAN. || egodard, CV configuré, VLAN configuré (par contre l'utilisation de &amp;lt;code&amp;gt;ether4&amp;lt;/code&amp;gt; est impossible), MV avec deux interfaces, correctement configurée en IPv4, pas d'adresse obtenue par DHCP, problème de l'OpenWRT, routeur OpenWRT avec les bonnes interfaces, l'adresse IPv4 sur SE5 est donnée avec un mauvais masque, linterface &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; reçoit bien son adresse IPv4 par DHCP.&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || khabre, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface, pas de configuration IPv4 correcte || asellali, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, une seule interface, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || rfarault, CV configuré, VLAN configuré mais configuration commentée (pourquoi donc ?!), MV lancée et correctement configurée en IPv4, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son @IPv4 à cause de l'absence d'interface VLAN. || CV configuré, VLAN configuré, MV avec deux interfaces, correctement configurée en IPv4, un routeur avec les deux interfaces demandées, pas d'adresse IPv4 sur SE5, serveur DHCP fonctionnel.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 02/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! MV &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; !! MV &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; !! Routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet, une IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
| IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.180, une IPv6 routée sur Internet, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel (si ? non, inversion des &amp;lt;code&amp;gt;vif&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| image disque du fichier de configuration non présente sur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt;&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas de fichier de configuration&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le fichier de configuration&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.116, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe01:754c, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.191, une IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le fichier de configuration, création du routeur impossible&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet, pas d'IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 05/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Pour utiliser l'interface Web LuCi des openWRT à partir d'une zabeth :&lt;br /&gt;
* vérifiez que vous avez bien une IPv6 routée sur IPv6 (avec &amp;lt;code&amp;gt;ip address show dev eth0&amp;lt;/code&amp;gt;, l'adresse commence par &amp;lt;code&amp;gt;2001:660:4401:60b0:&amp;lt;/code&amp;gt;) ;&lt;br /&gt;
* si vous n'en avez pas, prenez le suffixe (les derniers 8 octets de l'adresse locale, celle qui commence par &amp;lt;code&amp;gt;fe80::&amp;lt;/code&amp;gt;) et créez votre adresse IPv6 routée par la commande :&lt;br /&gt;
  ip address add dev eth0 2001:660:4401:60b0:&amp;lt;suffixe&amp;gt;/64&lt;br /&gt;
bien entendu vous n'aurez oublié de rajouter la route IPv6 par défaut vers le routeur de la promotion :&lt;br /&gt;
  ip -6 route add default via 2001:660:4401:60b0:6a9e:bff:fe46:5a76&lt;br /&gt;
* établissez un tunnel &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; avec la commande :&lt;br /&gt;
 zabethXX# ssh -L 6443:localhost:6443 root@IPv6&lt;br /&gt;
* connectez vous sur LuCi avec le navigateur de la zabeth pointant sur &amp;lt;code&amp;gt;https://localhost:6443&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attention l'ordre des interfaces &amp;lt;code&amp;gt;vif&amp;lt;/code&amp;gt; dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; a une importance.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! MV &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; !! MV &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; !! Routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet (puis &amp;lt;code&amp;gt;193.48.57.191&amp;lt;/code&amp;gt; donc une erreur), pas d'IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
| IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.180, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe31:b916, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen &lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, IPv4 sur VLAN50 : 172.26.145.107, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feff:4c44, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.167, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.184, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feaa:f293, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
| IPv4 sur CV : 10.0.69.156, IPv4 sur VLAN50 : 172.26.145.109, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe46:70cd, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.106, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.185, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fec6:169, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros&lt;br /&gt;
| IPv4 sur CV : 10.0.69.189, IPv4 sur VLAN50 : 172.26.145.111, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe14:cdb5, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.171, IPv4 sur VLAN50 : 172.26.145.110, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe5b:b2b5, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.188, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe5b:b2b6, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
| IPv4 sur CV : 10.0.69.100, IPv4 sur VLAN50 : 172.26.145.113, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fef9:2bb9, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas de machine virtuelle&lt;br /&gt;
| bloquage du serveur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; par installation du routeur openWRT sous la racine, machine non contactable en IPv6 sur le SE5&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton&lt;br /&gt;
| CV non configuré, machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudent&lt;br /&gt;
| pas d'adresse MAC dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut&lt;br /&gt;
| CV non configuré, machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| machine non contactable en IPv6 sur le SE5&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.191 (erreur !!), IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feb4:5ea4, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali&lt;br /&gt;
| machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.131, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.181, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Pas de changement sur les routeurs OpenWRT à 17h30.&lt;br /&gt;
&lt;br /&gt;
Pas de changement sur les MV d'&amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; à 18h00.&lt;br /&gt;
&lt;br /&gt;
Une seule modification sur les MV de &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; à 18h15 : la G7 (&amp;lt;code&amp;gt;g7jdelannoVM&amp;lt;/code&amp;gt;) est maintenant contactable (@IPv4 et @IPv6 sur le VLAN50) mais sans rien de plus.&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 06/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les routeurs openWRT (pas de relancement) :&lt;br /&gt;
&lt;br /&gt;
 G1 | IPv4 sur Internet : 193.48.57.191, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4&lt;br /&gt;
 G2 | IPv4 sur Internet : 193.48.57.180, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe31:b916, connexion à Internet en IPv4 possible&lt;br /&gt;
 G3 | IPv4 sur Internet : 193.48.57.184, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feaa:f293, connexion à Internet en IPv4 possible&lt;br /&gt;
 G4 | IPv4 sur Internet : 193.48.57.185, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fec6:169, connexion à Internet en IPv4 possible&lt;br /&gt;
 G5 | IPv4 sur Internet : 193.48.57.188, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe5b:b2b6, connexion à Internet en IPv4 possible&lt;br /&gt;
 G6 | IPv4 sur Internet : 193.48.57.187, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fef9:2bba, connexion à Internet en IPv4 possible&lt;br /&gt;
 G7 | Bad MAC address &lt;br /&gt;
 G8 | machine non contactable en IPv6 sur le SE5&lt;br /&gt;
 G9 | Rien&lt;br /&gt;
 G10 | IPv4 sur Internet : 193.48.57.186, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feb4:5ea4, pas de connexion à Internet en IPv4&lt;br /&gt;
 G11 | machine non contactable en IPv6 sur le SE5&lt;br /&gt;
 G12 | IPv4 sur Internet : 193.48.57.181, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les MV sur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 ==== g1kpatrikeevVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g2clemair1VM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g3tbrenierVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.167, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g4fnaudotVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.106, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g5mdelabyVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.171, IPv4 sur VLAN50 : 172.26.145.110, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe5b:b2b5, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g6bblackVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.113, IPv4 sur VLAN50 : 172.26.145.112, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe4a:d2be, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g7amoutonVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.114, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe59:7616, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g8esimonVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
 ==== g10egodardVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g11asellaliVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
 ==== g12mhalaouiVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les MV sur &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 ==== g1jcharleuxVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g2gthomasVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g3bnguyen1VM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.130, IPv4 sur VLAN50 : 172.26.145.107, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feff:4c44, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
 ==== g4drodenbuVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.156, IPv4 sur VLAN50 : 172.26.145.109, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe46:70cd, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g5pamorosVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.189, IPv4 sur VLAN50 : 172.26.145.111, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe14:cdb5, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g6hblgrimVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.100, IPv4 sur VLAN50 : 172.26.145.113, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fef9:2bb9, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
 ==== g7jdelannoVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.115, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe0f:aba1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g8mriffautVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
 ==== g10jdelcourVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g11khabreVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
 ==== g12rfaraultVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.131, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
&lt;br /&gt;
Trois groupes finissent à 17h : G2, G5 et G7.&lt;br /&gt;
&lt;br /&gt;
Un groupe à 17h20 : G6.&lt;br /&gt;
&lt;br /&gt;
Un groupe à 17h40 : G10.&lt;br /&gt;
&lt;br /&gt;
Le reste :&lt;br /&gt;
&lt;br /&gt;
  G8 -&amp;gt; installation du conteneur synapse&lt;br /&gt;
  G3 -&amp;gt; erreur à la connexion de la base de données, encodage ASCII&lt;br /&gt;
  G4 -&amp;gt; création de la base de données&lt;br /&gt;
  G12 -&amp;gt; problème à l'exécution du conteneur&lt;br /&gt;
  G11 -&amp;gt; essayent d'installer le conteneur synapse sur la zabeth&lt;br /&gt;
  G13 -&amp;gt; installation du mandataire inverse (reverse proxy nginx)&lt;br /&gt;
  G1 -&amp;gt; installation du conteneur synapse, se lance mais en échec&lt;br /&gt;
&lt;br /&gt;
G13 n'a pas mis à jour le tableau de répartition.&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3609</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3609"/>
		<updated>2023-12-20T14:44:31Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle.&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier.&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge.&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur.&lt;br /&gt;
***Création d'un fichier .txt afin de stocker les données du capteur toutes les minutes.&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes.&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas s'il est exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter notre programme python afin de récupérer les données à partir d'un json pour traiter ces données dans la VM.&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|vignette|Démonstration du protocole HTTP]]&lt;br /&gt;
&lt;br /&gt;
== Code de récupération de donnée (sur la raspberry) ==&lt;br /&gt;
Nous avons le scénario suivant : le capteur qui envoie en continue les données de distance à la raspberry via la liaison série.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc écrit un script python afin de récupérer ces données, les formatter dans un fichier format json dans le but de les envoyer sur la VM qui pourra traiter ces données avec l'émulateur obtenue via l'application NanoEdgeAI Studio.&lt;br /&gt;
&lt;br /&gt;
Nous allons vous expliquez le script que nous avons réalisés :&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3606</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3606"/>
		<updated>2023-12-20T14:19:23Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur&lt;br /&gt;
***Stockage des données dans un .txt&lt;br /&gt;
***Destruction automatique des fichiers de données ayant été crée il y a plus de 10 minutes&lt;br /&gt;
**L’émulateur de la librairie ne fonctionne pas si exécuté dans la raspberry... Nous l'exécutons désormais directement dans notre VM.&lt;br /&gt;
**Pour cela nous avons adapter de nouveau notre programme python permettant de récupérer les données afin de les stocker dans un json&lt;br /&gt;
***Création d'un fichier toutes les minutes (contenant au format json la date et les données au format csv)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|vignette]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3559</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3559"/>
		<updated>2023-12-20T08:31:51Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier&lt;br /&gt;
*Séance 4 :&lt;br /&gt;
**Essai d'utilisation de la librairie créée grâce à Nanoedge&lt;br /&gt;
**Amélioration du programme python permettant de récupérer les données du capteur&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|vignette]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3534</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3534"/>
		<updated>2023-12-19T14:52:34Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
*Séance 3:&lt;br /&gt;
**Entraînement d'un nouveau modèle&lt;br /&gt;
**Écriture d'un programme permettant de récupérer les données du capteur et de les écrire dans un fichier&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|vignette]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3509</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3509"/>
		<updated>2023-12-18T16:47:36Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;br /&gt;
[[Fichier:CaptureIndexBrenierNguyen.png|vignette]]&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3508</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3508"/>
		<updated>2023-12-18T16:46:49Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Code du client Python :'''&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
import argparse                                                                                                                            &lt;br /&gt;
import requests                                                                                                                            &lt;br /&gt;
import json                                                                                                                                &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
def send_json_to_server(url, json_file):                                                                                                   &lt;br /&gt;
    # Charger les données CSV depuis le fichier spécifié                                                                                   &lt;br /&gt;
    with open(json_file, 'r') as file:                                                                                                     &lt;br /&gt;
        data = json.load(file)                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # En-têtes spécifiant que vous envoyez du CSV                                                                                          &lt;br /&gt;
    headers = {'Content-Type': 'application/json'}                                                                                         &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Envoie de la requête HTTP POST avec les données                                                                                      &lt;br /&gt;
    response = requests.post(url, data=json.dumps(data), headers=headers)                                                                  &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Vérification de la réponse                                                                                                           &lt;br /&gt;
    if response.status_code == 200:                                                                                                        &lt;br /&gt;
        print('Requête envoyée avec succès!')                                                                                              &lt;br /&gt;
    else:                                                                                                                                  &lt;br /&gt;
        print(f'Erreur {response.status_code}: {response.text}')                                                                           &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:                                                                                                                 &lt;br /&gt;
    # Configurer les arguments en ligne de commande                                                                                        &lt;br /&gt;
    parser = argparse.ArgumentParser(description='Client Python pour envoyer des JSON via HTTP.')                                          &lt;br /&gt;
    parser.add_argument('url', type=str, help='URL du serveur')                                                                            &lt;br /&gt;
    parser.add_argument('json_file', type=str, help='Chemin vers le fichier JSON à envoyer')                                               &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Analyser les arguments                                                                                                               &lt;br /&gt;
    args = parser.parse_args()                                                                                                             &lt;br /&gt;
                                                                                                                                           &lt;br /&gt;
    # Appeler la fonction pour envoyer le JSON au serveur                                                                                  &lt;br /&gt;
    send_json_to_server(args.url, args.json_file) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Index permettant d'afficher le json de test que nous avons envoyé au serveur :'''&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Page d'Accueil&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;Bienvenue sur Mon Serveur&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;h2&amp;gt;Données POST reçues:&amp;lt;/h2&amp;gt;&lt;br /&gt;
    &amp;lt;ul id=&amp;quot;data&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Les données POST seront listées ici --&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;'''Capture montrant l'affichage d'un fichier json (sans aucun sens) envoyé au serveur depuis le client :'''&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:CaptureIndexBrenierNguyen.png&amp;diff=3507</id>
		<title>Fichier:CaptureIndexBrenierNguyen.png</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:CaptureIndexBrenierNguyen.png&amp;diff=3507"/>
		<updated>2023-12-18T16:44:21Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Démonstration de la récupération et de l'affichage du JSON reçu par le serveur&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3494</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3494"/>
		<updated>2023-12-18T16:37:05Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python3&amp;quot;&amp;gt;&lt;br /&gt;
from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
# Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;ul&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3491</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3491"/>
		<updated>2023-12-18T16:35:30Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Code du serveur Python :&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;nowiki&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;ul&amp;gt;'&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;nowiki&amp;gt;&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;&amp;lt;/nowiki&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;nowiki&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3490</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3490"/>
		<updated>2023-12-18T16:35:05Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code du serveur Python :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;nowiki&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;ul&amp;gt;'&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;nowiki&amp;gt;&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;&amp;lt;/nowiki&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;nowiki&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3489</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3489"/>
		<updated>2023-12-18T16:34:38Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code du serveur Python :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;code&amp;gt;from http.server import HTTPServer, BaseHTTPRequestHandler&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import json&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Stocker les requ  tes POST re  ues&lt;br /&gt;
&lt;br /&gt;
post_requests = []&lt;br /&gt;
&lt;br /&gt;
class CustomHTTPHandler(BaseHTTPRequestHandler):&lt;br /&gt;
&lt;br /&gt;
   def do_GET(self):&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/':&lt;br /&gt;
&lt;br /&gt;
           self.path = '/index.html'&lt;br /&gt;
&lt;br /&gt;
       if self.path == '/data':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'application/json')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(json.dumps(post_requests), 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
if self.path == '/index.html':&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           # Cr  er le contenu HTML avec les donn  es POST&lt;br /&gt;
&lt;br /&gt;
           content = '&amp;lt;nowiki&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Donn  es POST:&amp;lt;/h1&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;ul&amp;gt;'&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
           for item in post_requests:&lt;br /&gt;
&lt;br /&gt;
               content += f'&amp;lt;nowiki&amp;gt;&amp;lt;li&amp;gt;{item}&amp;lt;/li&amp;gt;&amp;lt;/nowiki&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           content += '&amp;lt;nowiki&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;'&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(content.encode('utf-8'))&lt;br /&gt;
&lt;br /&gt;
           return&lt;br /&gt;
&lt;br /&gt;
       try:&lt;br /&gt;
&lt;br /&gt;
file_to_open = open(self.path[1:]).read()&lt;br /&gt;
&lt;br /&gt;
           self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
           self.send_header('Content-type', 'text/html')&lt;br /&gt;
&lt;br /&gt;
           self.end_headers()&lt;br /&gt;
&lt;br /&gt;
           self.wfile.write(bytes(file_to_open, 'utf-8'))&lt;br /&gt;
&lt;br /&gt;
       except FileNotFoundError:&lt;br /&gt;
&lt;br /&gt;
           self.send_error(404, 'File Not Found: %s' % self.path)&lt;br /&gt;
&lt;br /&gt;
   def do_POST(self):&lt;br /&gt;
&lt;br /&gt;
       content_length = int(self.headers['Content-Length'])&lt;br /&gt;
&lt;br /&gt;
       post_data = self.rfile.read(content_length).decode('utf-8')&lt;br /&gt;
&lt;br /&gt;
       # Ajouter les donn  es POST    la liste&lt;br /&gt;
&lt;br /&gt;
       post_requests.append(post_data)&lt;br /&gt;
&lt;br /&gt;
       # Envoyer une rponse HTTP&lt;br /&gt;
&lt;br /&gt;
       self.send_response(200)&lt;br /&gt;
&lt;br /&gt;
       self.end_headers()&lt;br /&gt;
&lt;br /&gt;
self.wfile.write(b&amp;quot;POST request processed&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class HTTPServerV6(HTTPServer):&lt;br /&gt;
&lt;br /&gt;
   address_family = socket.AF_INET6&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
&lt;br /&gt;
   server_address = ('::', 8888)  #  ^icoute sur toutes les interfaces IPv6, p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   httpd = HTTPServerV6(server_address, CustomHTTPHandler)&lt;br /&gt;
&lt;br /&gt;
   print(&amp;quot;Serveur actif sur le port&amp;quot;, 8888)&lt;br /&gt;
&lt;br /&gt;
   httpd.serve_forever() &amp;lt;nowiki&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3476</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3476"/>
		<updated>2023-12-18T16:23:52Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur python&lt;br /&gt;
**Mise en place du client python&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3473</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3473"/>
		<updated>2023-12-18T16:21:49Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;br /&gt;
** Installation de NanoEdge&lt;br /&gt;
** Installation de STM32cube&lt;br /&gt;
** Installation de l'OS pour la Raspberry dans la carte micro SD&lt;br /&gt;
** Prise en main de Nanoedge, de nucléo et de STM32cube&lt;br /&gt;
** Début de réflexion sur l'application (métrologie)&lt;br /&gt;
*Séance 2:&lt;br /&gt;
**Mise en place du serveur&lt;br /&gt;
**Mise en place du client&lt;br /&gt;
**Test réussi de communication entre client et serveur via http&lt;br /&gt;
**Programmation de la carte nucléo pour transfert de valeur via liaison série&lt;br /&gt;
**Suite réflexion sur l'application (reconnaissance alphabet langue des signes, mouvement)&lt;br /&gt;
**Choix de l'application : reconnaissance d'objets appliqué aux fournitures scolaires&lt;br /&gt;
**Entraînement des modèles pour les différentes applications cités précédemment&lt;br /&gt;
**Finalement : entraînement à la reconnaissance d'objets de fournitures scolaires&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3466</id>
		<title>SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI/eceai_2023/2024/Brenier-Nguyen&amp;diff=3466"/>
		<updated>2023-12-18T16:10:30Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : Page créée avec « * Séance 1 : ** Création et configuration de la VM sur Chassiron »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Séance 1 :&lt;br /&gt;
** Création et configuration de la VM sur Chassiron&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI_2023/2024&amp;diff=3464</id>
		<title>SE5 ECEAI 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_ECEAI_2023/2024&amp;diff=3464"/>
		<updated>2023-12-18T16:09:26Z</updated>

		<summary type="html">&lt;p&gt;Tbrenier : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SE5 ECEAI 2023/2024&lt;br /&gt;
&lt;br /&gt;
Groupe Delannoy - Lemaire : [[SE5 ECEAI/eceai 2023/2024/jcie]]&lt;br /&gt;
&lt;br /&gt;
Groupe Rodenburg - Thomas → [[Gabidann|SE5 ECEAI/eceai 2023/2024/gabidann]]&lt;br /&gt;
&lt;br /&gt;
Groupe Halaoui - Farault : [[SE5 ECEAI/eceai 2023/2024/FaraultHalaoui]]&lt;br /&gt;
&lt;br /&gt;
Groupe Godard - Delcourt : [[SE5 ECEAI/eceai 2023/2024/GodardDelcourt]]&lt;br /&gt;
&lt;br /&gt;
Groupe Naudot - Riffaut : [[SE5 ECEAI/eceai_2023/2024/NaudotRiffaut]]&lt;br /&gt;
&lt;br /&gt;
Groupe Amoros - Delaby : [[SE5 ECEAI/eceai 2023/2024/AmorosDelaby]]&lt;br /&gt;
&lt;br /&gt;
Groupe Charleux - Habre : [[SE5 ECEAI/eceai 2023/2024/CharleuxHabre]]&lt;br /&gt;
&lt;br /&gt;
Groupe Balbastre - Simon : [[SE5 ECEAI/eceai 2023/2024/BalbastreSimon]]&lt;br /&gt;
&lt;br /&gt;
Groupe Patrikeev - Mouton : [[SE5 ECEAI/eceai 2023/2024/Patrikeev-Mouton]]&lt;br /&gt;
&lt;br /&gt;
Groupe Brenier - Nguyen : [[SE5 ECEAI/eceai 2023/2024/Brenier-Nguyen]]&lt;br /&gt;
&lt;br /&gt;
== Groupe Vallée-Sellali ==&lt;br /&gt;
'''Séance n°1:'''&lt;br /&gt;
&lt;br /&gt;
Machine virtuelle créée sur chassiron : &lt;br /&gt;
&lt;br /&gt;
Hostname       :  ValSel&lt;br /&gt;
&lt;br /&gt;
Distribution    :  bookworm&lt;br /&gt;
&lt;br /&gt;
Stockage        : 10G&lt;br /&gt;
&lt;br /&gt;
Mémoire vive : 1G&lt;br /&gt;
&lt;br /&gt;
Mot de passe : glopglop&lt;br /&gt;
&lt;br /&gt;
Les fichiers /etc/network/interfaces,  /etc/resolv.conf et /etc/apt/sources.list ont été modifiés comme demandés.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Raspberry 4 :&lt;br /&gt;
&lt;br /&gt;
Communication via le port série possible&lt;br /&gt;
&lt;br /&gt;
Login : pifou Pwd : pasglop&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STM32F401RE : Nanoedge et IDE installés, conception d'un code pour tester le capteur en cours&lt;/div&gt;</summary>
		<author><name>Tbrenier</name></author>
	</entry>
</feed>