
=======================================================================================
  __DOC_Version_v74 -- Documentation Systeme COMPLETE et FINALE
  Projet  : WemosESP32_LittleFS_CmdLineLogTelnetBlue_Pcaptif
  Version : v74  (version courante -- v74 cosmetique + correction MAC SetMac + CmdLine v24)
  Date    : 20/05/2026
  Auteur  : Jean-Marc Biechy
             Ecole d'Electronique Informatique et Reseau
             Institution Saint-Jean -- Colmar -- France
=======================================================================================

  FICHIERS SOURCE ACTIFS (version finale) :
    WemosESP32_LittleFS_CmdLineLogTelnetBlue_Pcaptif_v74.ino
    Shell_CmdLine_LittleFS_WiFi.h
    Driver_ESP32_Reseau_PortailCaptif.h
    ServeurWEB.h
    utils.h

=======================================================================================
  INTRODUCTION -- QU'EST-CE QUE IoToS ?
=======================================================================================

  IoToS (Internet of Things Operating System) est un micro-systeme d'exploitation
  embarque concu pour les microcontroleurs ESP32 (et variantes ESP8266).

  Son objectif est de fournir, sur une seule puce WiFi bon marche, l'ensemble des
  couches logicielles necessaires a un objet connecte industriel ou pedagogique :

    - Un noyau (kernel) cooperatif base sur la loop Arduino, qui ordonnance des
      "taches" (services) sans preemption ni RTOS.
    - Un shell (ligne de commande) accessible en Serial, Telnet et Bluetooth,
      permettant de configurer et piloter le systeme sans reflasher le firmware.
    - Des services reseau : serveur WEB HTTP/AJAX, serveur FTP, client NTP,
      portail captif WiFi, ping ICMP.
    - Un gestionnaire de fichiers LittleFS (equivalent d'une carte SD interne).
    - Un datalogger CSV horodate par NTP.
    - Une robustesse logicielle : watchdog materiel, ping de supervision,
      reboot automatique, comptage des reboots en EEPROM.

  ANALOGIE SYSTEME :

    +------------------+-----------------------------------------------------+
    | Couche OS        | Equivalent IoToS ESP32                              |
    +------------------+-----------------------------------------------------+
    | Shell (cmd.exe)  | Shell_CmdLine_LittleFS_WiFi.h  (commandes CLI)      |
    | Drivers          | Driver_ESP32_Reseau_PortailCaptif.h  (WiFi, MAC)    |
    | Systeme fichiers | LittleFS  (partition Flash interne)                 |
    | API reseau       | ServeurWEB.h / SimpleFTPServer / NTPClient          |
    | Noyau / Kernel   | loop() Arduino  (ordonnancement cooperatif)         |
    | BIOS / Boot      | setup() Arduino  (initialisation sequentielle)      |
    | Registres config | EEPROM 512 octets  (struct conf_t persistante)      |
    | Watchdog         | Ticker ISRwatchdog  (reboot si loop bloquee > 1 min)|
    +------------------+-----------------------------------------------------+

  RESUME EN UNE PHRASE :
    IoToS transforme une carte ESP32 WeMos D1 R32 en une "prise IP" intelligente
    administrable a distance, capable de piloter une LED, enregistrer des donnees,
    servir des pages WEB et accepter des connexions en ligne de commande via Serial,
    Telnet ou Bluetooth.

  CE QUE IoToS NE FAIT PAS (perimetre negatif) :
    - Pas de RTOS / preemption : les taches ne sont pas des threads independants.
    - Pas de chiffrement TLS (HTTPS) : le serveur WEB est en HTTP simple.
    - Pas de base de donnees : le datalogger est un simple fichier CSV.
    - Pas de pile IPv6.
    - Pas de gestion de plusieurs LEDs ou actionneurs complexes (1 sortie GPIO).
    - Pas de protocole MQTT, LoRa, Zigbee.


=======================================================================================
  0. INSTALLATION
=======================================================================================

  ---- 0.1  OUTILS REQUIS ----

    Logiciel                  Version         Lien
    ----------------------    -----------     ----------------------------------------
    IDE Arduino               2.3.8           https://www.arduino.cc/en/software
    Librairie ESP32           3.3.8           https://dl.espressif.com/dl/package_esp32_index.json
    Python (pour upload FS)   3.x             (inclus dans l'IDE Arduino 2.x)

  ---- 0.2  INSTALLATION DE L'IDE ARDUINO ----

    1. Telecharger et installer Arduino IDE 2.3.8.
    2. Ouvrir : Fichier --> Preferences
    3. Dans "URL de gestionnaire de cartes supplementaires" ajouter :
         https://dl.espressif.com/dl/package_esp32_index.json
    4. Outils --> Gestionnaire de cartes --> rechercher "esp32" par Espressif Systems
       Installer la version 3.3.8

  ---- 0.3  CONFIGURATION DE LA CARTE ----

    Outils --> Type de carte --> ESP32 Arduino --> WEMOS D1 R32

    Reglages recommandes :
      Upload Speed       : 921600
      CPU Frequency      : 240 MHz
      Flash Frequency    : 80 MHz
      Flash Mode         : QIO
      Flash Size         : 4MB (32Mb)
      Partition Scheme   : voir tableau ci-dessous

    TABLEAU DES SCHEMES DE PARTITION (Flash 4 MB) :

      Nom                               | APP    | OTA    | LittleFS | OTA ?
      ----------------------------------|--------|--------|----------|------
      Default 4MB with SPIFFS (defaut)  | 1.25MB | 1.25MB | 1.375MB  | Oui
      No OTA (Large App)                | 2.0MB  |   -    | 1.875MB  | Non
      Minimal SPIFFS (Large App + OTA)  | 1.875MB| 1.875MB| 0.120MB  | Oui

      --> Recommande sans OTA  : "No OTA (Large App)"  -- plus de RAM app, plus de LittleFS
      --> Recommande avec OTA  : "Default 4MB with SPIFFS"

  ---- 0.4  LIBRAIRIES A INSTALLER ----

    Dans Outils --> Gerer les bibliotheques :

      Bibliotheque              Version     Auteur / Source
      -----------------------   ---------   ---------------------------------
      ESP32Ping                 1.7         dvarrel / bluemurder
      NTPClient                 3.1.0       Fabrice Weinberg
      SimpleFTPServer           3.0.2       Renzo Mischianti
      CmdLine_Multiplatform     v24         (librairie modifiee -- voir note)
      Ticker                    (incluse dans core ESP32)
      EEPROM                    (incluse dans core ESP32)
      LittleFS                  (incluse dans core ESP32 3.x)
      WiFi                      (incluse dans core ESP32)
      DNSServer                 (incluse dans core ESP32)
      ArduinoOTA                (incluse dans core ESP32, si ENABLE_OTA actif)
      BluetoothSerial           (incluse dans core ESP32, si ENABLE_Bluetooth actif)

      NOTE CmdLine v24 : la librairie CmdLine_Multiplatform a ete fortement modifiee
      pour supporter Telnet et Bluetooth. Utiliser la version v24 du projet.
      En v24, write(uint8_t) est correctement implemente sur les 3 canaux
      (Serial + Telnet + Bluetooth) -- corrige l'ambiguite vtable C++ de v23.
      Consequence : cmdLine.print(val, HEX) fonctionne sans crash en v24.

      NOTE ESP32Ping : les fichiers ping.h, ping.cpp, ESP32Ping.h, ESP32Ping.cpp
      ont ete modifies pour exposer minTime() / maxTime() / totalSent() /
      totalReceived(). Remplacer les fichiers dans :
        D:\Arduino\libraries\ESP32Ping\

  ---- 0.5  UPLOAD DU FIRMWARE ----

    1. Connecter la carte WeMos D1 R32 en USB.
    2. Selectionner le bon PORT COM dans Outils --> Port.
    3. Cliquer sur le bouton Upload (fleche droite).
    4. A la premiere connexion Serial (115200 bauds) :
       Taper "stop" dans les 3 secondes pour acceder au shell.
       Configurer SSID, mot de passe WiFi, IP, puis taper "save" et "reset".

  ---- 0.6  UPLOAD DE LA PARTITION LittleFS (fichiers WEB) ----

    Les fichiers WEB (index.html, ConfIP_SSID_JS.html) doivent etre uploades
    dans la partition LittleFS separement du firmware.

    METHODE RECOMMANDEE -- Script batch Windows :

      1. Placer les fichiers HTML dans le sous-repertoire /data/ du projet Arduino.
      2. Lancer le script :
           upload_littleFS_WEMOS_ESP32_D1_R32_v6.bat
      3. Entrer le numero de PORT COM quand demande.
      4. Entrer le type de partition (correspondant au scheme Arduino configure).
      5. Le script detecte automatiquement la version de mklittlefs installee.

      IMPORTANT : utiliser mklittlefs (v4.0.2+), PAS mkspiffs.
      Les formats binaires sont incompatibles.
      mklittlefs detecte via : for /d dans le dossier tools d'Arduino15.

    METHODE ALTERNATIVE (IDE Arduino 2.x) :
      Ctrl+Shift+P --> "Upload LittleFS to Pico/ESP8266/ESP32"
      (necessite le plugin arduino-littlefs-upload)


=======================================================================================
  1. IDENTIFICATION GENERALE
=======================================================================================

  Nom du programme  : WemosESP32_LittleFS_CmdLineLogTelnetBlue_Pcaptif_v74.ino
  Fichiers inclus   : Shell_CmdLine_LittleFS_WiFi.h
                      Driver_ESP32_Reseau_PortailCaptif.h
                      ServeurWEB.h
                      utils.h

  Version           : v74  (version courante -- v74 + correction SetMac + CmdLine v24)
  Date compilation  : 20/05/2026
  Auteur            : Jean-Marc Biechy
  Institution       : Ecole d'Electronique Informatique et Reseau
                      Institution Saint-Jean -- Colmar -- France
  Contact           : Cours d'informatique reseaux 2026

  Plateforme cible  :
    Materiel        : WeMos D1 R32  (module ESP32 WROOM-32, Flash 4 MB)
    SoC             : Espressif ESP32  (Xtensa LX6 dual-core 240 MHz)
    RAM             : 520 KB SRAM (327 KB disponible en mode applicatif)
    RAM utilisee    : ~57.5 KB variables globales / ~198 KB libres (BT desactive)
    RAM disponible  : ~270 KB libres avec Bluetooth desactive
    RAM avec BT ON  : ~198 KB libres (Bluedroid consume ~70 KB supplementaires)
    Flash firmware  : ~1.08 MB (82% de 1.31 MB en partition "No OTA")
    LittleFS        : 1.375 MB a 1.875 MB selon partition

  Compilateur       : IDE Arduino 2.3.8
  Core ESP32        : Espressif Systems 3.3.8
  Langage           : C++ Arduino (C++17 avec extensions Xtensa)

  Licence           : GNU LGPL v2.1
    URL             : https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
    Code applicatif (.ino) : reste la propriete de l'auteur


=======================================================================================
  2. ROLE / OBJECTIF
=======================================================================================

  RAISON D'ETRE :
    Transformer une carte ESP32 WeMos D1 R32 en un noeud IoT administrable
    a distance, offrant une interface Web, une ligne de commande reseau,
    un enregistrement de donnees et une auto-guerison par supervision WiFi.

  FONCTIONS PRINCIPALES :

    +---+----------------------------+--------------------------------------------+
    | # | Service                    | Description                                |
    +---+----------------------------+--------------------------------------------+
    | 1 | Shell CLI                  | Ligne de commande Serial/Telnet/Bluetooth  |
    | 2 | Serveur WEB HTTP/AJAX      | Commande LED + configuration IP par WEB   |
    | 3 | Serveur FTP                | Acces aux fichiers LittleFS (FileZilla)    |
    | 4 | Client NTP                 | Horloge temps reel (pool.ntp.org UTC+1)    |
    | 5 | Portail Captif (AP)        | Configuration WiFi sans infrastructure     |
    | 6 | Datalogger CSV             | Enregistrement horodate sur LittleFS       |
    | 7 | Ping supervision           | Reboot auto si passerelle injoignable      |
    | 8 | OTA (optionnel)            | Mise a jour firmware par WiFi              |
    | 9 | Watchdog                   | Reboot si loop bloquee > 1 minute          |
    |10 | EEPROM persistance         | Sauvegarde de la configuration reseau      |
    +---+----------------------------+--------------------------------------------+

  CE QUE LE PROGRAMME NE FAIT PAS :
    - Pas de HTTPS / TLS / chiffrement des communications
    - Pas de plusieurs canaux de commande simultanes (1 client Telnet a la fois)
    - Pas de multitache preemptif (cooperatif uniquement via loop)
    - Pas de protocole MQTT, CoAP, LoRa, Zigbee
    - Pas de gestion de plusieurs actionneurs (1 LED sur D2 / GPIO26)
    - Pas de stockage SD externe (LittleFS interne uniquement)

  PLACE DANS LE SYSTEME :

    Internet
       |
    Routeur / Box (gateway : 192.168.0.253 par defaut)
       |
    Reseau LAN  192.168.0.0/24
       |
    ESP32 WeMos D1 R32  (IP : 192.168.0.11 par defaut, port WEB : 80)
       |
       +--- Navigateur WEB (utilisateur)      [HTTP port 80]
       +--- Client Telnet Putty/Kitty         [TCP port 23]
       +--- Client FTP FileZilla              [TCP port 21 + PASV 50009]
       +--- IDE Arduino / Putty Serial        [UART 115200 bauds]
       +--- Application Bluetooth Android/iOS [BT classique, optionnel]
       |
    Actionneur : LED sur GPIO 26 (connecteur D2 Grove)


=======================================================================================
  3. ENTREES
=======================================================================================

  ---- 3.1  ENTREES PHYSIQUES ----

    Source          Broche    GPIO   Type         Format / Plage
    --------------  --------  -----  -----------  ---------------------------
    LED commande    D2        26     Sortie GPIO  boolean : 0=OFF / 1=ON
    LED interne     BUILTIN   2      Sortie GPIO  boolean (coeur / AP blink)
    Tension VCC     ADC interne      float        rom_phy_get_vdd33() / 1000 V
                                                  Typique : 3.3 V +/- 5%

    Connecteurs Grove disponibles (non utilises dans cette version) :
      AN0=GPIO2  AN1=GPIO4   AN2=GPIO35  AN3=GPIO34  AN4=GPIO36  AN5=GPIO39
      D3=GPIO25  D4=GPIO17   D5=GPIO16   D6=GPIO27   D7=GPIO14   D8=GPIO12
      D9=GPIO13  D10=GPIO5   D11=GPIO23  D12=GPIO19  D13=GPIO18

  ---- 3.2  ENTREES SERIE (UART) ----

    Canal   Vitesse     Format    Usage
    ------  ----------  --------  -----------------------------------------
    Serial  115200 bps  8N1       Shell CLI -- commandes texte ASCII + CR/LF
                                  Pendant le boot : "stop" dans les 3s
                                  pour bloquer la connexion WiFi automatique

    Comportement si absent : le boot WiFi demarre automatiquement apres 3s.

  ---- 3.3  ENTREES RESEAU ----

    Canal    Port   Protocole   Format entree
    -------  -----  ----------  --------------------------------------------------
    Telnet   23     TCP         Texte ASCII + CR/LF (commandes shell identiques)
    HTTP     80     TCP/HTTP    GET / POST HTTP 1.1 -- URL + corps formulaire
                                Buffer : char HTTP_req[1024]
    FTP      21     TCP/FTP     Protocole FTP standard (commandes FTP ASCII)
    FTP PASV 50009  TCP         Transfert de donnees FTP passif
    Bluetooth --    BT classique Texte ASCII + CR/LF (meme shell que Serial)
                                (actif uniquement si #define ENABLE_Bluetooth)

    Authentification Telnet :
      Optionnelle -- activable par : login ON
      Mot de passe par defaut : "changerLeMotDePasse"
      Anti-brute-force : delai double a chaque erreur (5s -> 10s -> 20s ... max 7 jours)

    Authentification WEB :
      Optionnelle -- activable par : loginWEB ON
      Schema : HTTP Basic Authentication (Base64)
      Credential par defaut : "dXNlcjpwYXNz" = "user:pass" en Base64
      Modifier via : https://www.base64encode.org/

    Authentification FTP :
      Login/MdP par defaut : esp32 / esp32
      1 seule connexion simultanee (regler dans FileZilla)

  ---- 3.4  ENTREES EEPROM (configuration persistante) ----

    La structure conf_t est lue depuis l'EEPROM au boot (adresse base = 5).
    Taille EEPROM allouee : 512 octets.

    Validation : champ conf.validity == VALID (1000043)
    Si invalide (premiere utilisation ou VALID change) : chargement de default_conf.

    ATTENTION : selon l'historique v73g old4, la valeur VALID a ete incrementee
    jusqu'a 1000271 pour invalider l'ancienne EEPROM lors de l'ajout du champ
    nbrRebootperteWifi. Verifier la valeur reelle dans le .ino avant tout flash.

    Champ conf_t          Type            Par defaut            Description
    --------------------  --------------  --------------------  -----------------------
    validity              uint32_t        1000043 (*)           Marqueur validation EEPROM
    nameSystem[40]        char[]          "ESP32"               Nom systeme (BT + OTA)
    telnetPassword[40]    char[]          "changerLeMotDePasse" Mot de passe CLI/Telnet
    login_cmdTelnetSwitch boolean         0 (OFF)               Verrou CLI actif/inactif
    modeAPswitch          boolean         0                     Mode portail captif auto
    SrvWEBswitch          boolean         1 (ON)                Serveur WEB actif
    SrvFTPswitch          boolean         1 (ON)                Serveur FTP actif
    led                   boolean         0 (OFF)               Etat LED au boot
    macCustom             boolean         0 (auto)              MAC physique ou custom
    mac[6]                uint8_t[]       DE:AD:BE:EF:FE:B1     MAC si custom
    dhcp                  boolean         0 (IP fixe)           Mode DHCP
    ip[4]                 uint8_t[]       192.168.0.11          Adresse IP fixe
    subnet[4]             uint8_t[]       255.255.255.0         Masque sous-reseau
    gateway[4]            uint8_t[]       192.168.0.253         Passerelle
    port                  uint16_t        80                    Port serveur WEB
    ssid[40]              char[]          "BI"                  SSID WiFi
    pass[40]              char[]          "1407@Merlamin"       Mot de passe WiFi
    loginWEB              boolean         0 (OFF)               Auth WEB active
    loginPasswordWEB[40]  char[]          "dXNlcjpwYXNz"        Credential WEB Base64
    loginFTP[40]          char[]          "esp32"               Login FTP
    passwordFTP[40]       char[]          "esp32"               Mot de passe FTP
    dataloggerSwitch      boolean         0 (OFF)               Datalogger actif
    fichierEnCours[40]    char[]          "/datalogger.csv"     Fichier datalogger
    nbrReboot             uint8_t         0                     Compteur reboots WiFi
    timeReboot            unsigned long   0                     Horodatage dernier reboot
    nbrRebootperteWifi    uint32_t        0                     Reboots perte passerelle
    debug                 boolean         0 (OFF)               Mode debug actif

    (*) Valeur a verifier dans le .ino -- peut etre 1000271 apres v73g.

    Comportement si EEPROM corrompue ou VALID different :
      --> default_conf chargee automatiquement (IP 192.168.0.11, login esp32/esp32)
      --> A la prochaine commande "save" la nouvelle conf est ecrite

  ---- 3.5  ENTREES LittleFS (fichiers) ----

    Fichier                  Usage
    -----------------------  --------------------------------------------------
    /index.html              Page WEB principale (commande LED)
    /ConfIP_SSID_JS.html     Page WEB configuration reseau WiFi
    /datalogger.csv          Fichier de donnees CSV (cree si absent par "create")
    /Log.txt                 Fichier log debug (cree si debug ON)

    Comportement si LittleFS absent ou non monte :
      --> Boot_FAILED affiche en Serial
      --> FTP desactive (FSok = 0)
      --> Serveur WEB renvoie erreur a l'envoi des fichiers HTML


=======================================================================================
  4. SORTIES
=======================================================================================

  ---- 4.1  SORTIES GPIO ----

    Broche      GPIO   Signal          Condition de production
    ----------  -----  --------------  -----------------------------------------
    D2 (Grove)  26     LED commande    Commande WEB (BoutonON/OFF) ou CLI "LED on/off"
    BUILTIN     2      LED status      Mode STA : clignotement 1 Hz
                                       Mode AP  : clignotement rapide 10 Hz
                                       Boot/erreur : HIGH (eteinte)

  ---- 4.2  SORTIES SERIE ----

    Canal    Format       Contenu
    -------  ----------   --------------------------------------------------------
    Serial   ASCII ANSI   Messages de boot codes couleur [  OK  ] / [FAILED]
                          Log de supervision (ping, watchdog, reboot)
                          Echo du shell CLI (identique Telnet)

    Format boot : [  OK  ] ou [FAILED] precede chaque etape d'initialisation.
    Codes couleur ANSI 256 : vert fond noir (OK), blanc fond rouge (FAILED).

  ---- 4.3  SORTIES RESEAU ----

    Canal    Port   Contenu                           Format
    -------  -----  --------------------------------  --------------------------
    Telnet   23     Reponses shell + banner connexion  ASCII + ANSI couleur CRLF
    HTTP     80     Pages HTML statiques               text/html (fichiers LittleFS)
                    Reponses AJAX                     text/xml (balises XML)
                    Authentification refusee          HTTP 401 + WWW-Authenticate
    FTP      21     Protocole FTP standard            ASCII commandes FTP
    BT       --     Reponses shell                    ASCII (identique Serial)

    Format AJAX (reponses XML vers navigateur) :
      <LED>ON</LED>   ou   <LED>OFF</LED>
      Balises : SSID, MotPass, DHCP, IPA..IPD, MSRA..MSRD, GATA..GATD, LOG

  ---- 4.4  SORTIES FICHIERS LittleFS ----

    Fichier          Declencheur              Format ligne
    ---------------  -----------------------  ----------------------------------------
    /datalogger.csv  Commande "datalogger on"  "Date;Heure;ON|OFF\n"
                     + evenement LED ON/OFF    ex: "2026-05-20;14:32:01;ON"
                     Entete : "Date ; Heure ; Etat led"
    /Log.txt         Commande "debug on"       "Date;Heure;TexteMessage\n"
                     + appels DebugProg()

  ---- 4.5  EFFETS DE BORD (modifications d'etat global) ----

    Action                    Effet persistant
    ------------------------  -------------------------------------------------------
    Commande "save"           EEPROM.put() + EEPROM.commit() -> conf_t persistee
    Ping passerelle HS        conf.nbrRebootperteWifi++ -> EEPROM -> ESP.restart()
    3 reboots WiFi echec      conf.nbrReboot = 3 -> EEPROM -> WiFiModeAP() ou restart
    Commande "defaults"       default_conf chargee en RAM (sans save : volatile)
    Commande "format"         LittleFS.format() -> TOUS les fichiers effaces


=======================================================================================
  5. FONCTIONS INTERNES
=======================================================================================

  ---- 5.1  ARCHITECTURE FICHIERS ----

    Fichier                              Role
    -----------------------------------  -----------------------------------------
    .ino  (fichier principal)            Declarations, setup(), loop(), InfoVersion()
    Driver_ESP32_Reseau_PortailCaptif.h  Connexion WiFi, portail captif, MAC
    Shell_CmdLine_LittleFS_WiFi.h        Commandes CLI (50+ commandes)
    ServeurWEB.h                         Serveur HTTP, pages WEB, AJAX
    utils.h                              Fonctions communes : boot, Datalogger,
                                         DebugProg, PrintMAC, TestValidityIP,
                                         PremiereConnexionTelnet/Serial, PrintProgmem

  ---- 5.2  ORDONNANCEMENT DES TACHES DANS loop() ----

    Ordre   Tache                  Condition d'execution          Periodicite
    ------  ---------------------  ----------------------------   ----------------
    1       cmdLine.update()       Toujours                       Chaque iteration
    2       cmdLineBT.update()     Si ENABLE_Bluetooth            Chaque iteration
    3       Telnet accept          Si wifiSwitch==1               Chaque iteration
    4       OTA handle             Si ENABLE_OTA && wifiSwitch    Chaque iteration
    5       Serveur WEB            Si wifiSwitch && SrvWEBswitch  Chaque iteration
    6       Serveur FTP            Si wifiSwitch && SrvFTPswitch  Chaque iteration
    7       Banner Telnet          Premier client connecte        A la connexion
    8       Banner Serial          Reconnexion Serial             A la reconnexion
    9       DNS portail captif     Si wifiSwitch==1               Chaque iteration
    10      Timer AP (timeout)     Si mode AP actif               Verification 1s
    11      Coeur LED BUILTIN      Toujours                       1 Hz (STA) / 10 Hz (AP)
    12      Ping Tester            Si STA && timer                Toutes les 10 min
    13      Watchdog reset         Toujours                       Chaque iteration

  ---- 5.3  SEQUENCE DE BOOT (setup) ----

    +--[1]--> Serial 115200 bauds + InfoVersion() (banniere ANSI)
    +--[2]--> Affichage etat firmware (#ifdef : OTA, Bluetooth)
    +--[3]--> Mesure tension VCC (rom_phy_get_vdd33)
    +--[4]--> EEPROM.begin(512) + LoadConfEEPROM()
    +--[5]--> GPIO : pinMode LED D2 + LED_BUILTIN
    +--[6]--> LittleFS.begin(false) --> FSok = 0 ou 1
    +--[7]--> Initialisation_Wifi_ESP() --> wifiSwitch = 0 ou 1
    |           Compte a rebours 3s --> "stop" pour bloquer
    |           Wifi_ESP_START() : mode STA ou AP selon nbrReboot
    +--[8]--> Si wifiSwitch==1 :
    |           OTA.begin() si ENABLE_OTA
    |           serverTelnet.begin() port 23
    |           ftpSrv.begin() si FSok
    |           timeClient.begin() + update() si STA && etatNTP
    |           server.begin() port conf.port (defaut 80)
    +--[9]--> cmdLine.begin() + secondTick.attach(ISRwatchdog)

  ---- 5.4  MACHINE D'ETAT CONNEXION WiFi ----

    [Boot]
       |
       v
    [Compte a rebours 3s] -- "stop" --> [CLI Serial uniquement -- WiFi OFF]
       |
       v
    [WiFi.begin(SSID, pass)]
       |
       +-- Connexion OK dans 10s --> [Mode STA -- fonctionnement normal]
       |
       +-- Echec 10s --> nbrReboot++
                  |
                  +-- nbrReboot < 3 --> ESP.restart()
                  |
                  +-- nbrReboot == 3 && modeAPswitch==1
                              |
                              v
                        [WiFiModeAP()]
                        IP : 10.0.0.1
                        SSID : ESP_10.0.0.1
                        Timer 5 min --> ESP.restart()

  ---- 5.5  COMMANDES SHELL DISPONIBLES ----

    CATEGORIE SYSTEME :
      help / man / ?         Affiche l'aide complete
      print / ifconfig / p   Affiche la configuration complete (IP, WiFi, LED...)
      version                Affiche la version du firmware
      ram                    Affiche la RAM libre (ESP.getFreeHeap())
      reset / restart / reboot  Redemarre l'ESP32 et recharge l'EEPROM
      save                   Sauvegarde la configuration en EEPROM
      reload                 Recharge la configuration depuis l'EEPROM
      defaults               Recharge la configuration par defaut (IP 192.168.0.11)
      saveconf <fichier>     Sauvegarde la conf dans un fichier LittleFS
      loadconf <fichier>     Charge la conf depuis un fichier LittleFS
      Name <nom>             Modifie le nom du systeme (BT + OTA hostname)
      debug on/off           Active le log dans /Log.txt
      test                   Fonction de test (vide en production)

    CATEGORIE LED / ACTIONNEURS :
      LED on / LED off       Allume / eteint la LED sur D2 (GPIO26)

    CATEGORIE RESEAU :
      ip <x.x.x.x>          Modifie l'adresse IP
      subnet <x.x.x.x>      Modifie le masque de sous-reseau
      gateway <x.x.x.x>     Modifie la passerelle
      port <0-65535>         Modifie le port du serveur WEB (defaut 80)
      dhcp on/off            Active/desactive le DHCP
      validmac auto/user     Selectionne MAC physique ou MAC custom
      mac <XX:XX:XX:XX:XX:XX> Modifie l'adresse MAC custom
      SSID <nom>             Modifie le SSID WiFi
      wifipass <motdepasse>  Modifie le mot de passe WiFi
      wifi on/off            Active/desactive le WiFi
      ModeAP on/off          Active/desactive le basculement en portail captif
      infowifi               Affiche les informations de connexion WiFi
      stop / s               Arrete la connexion WiFi (CLI uniquement)
      ping <IP ou URL>       Envoie 4 pings ICMP -- affiche min/moy/max

    CATEGORIE SECURITE :
      login on/off/<mdp>     Verrouille/deverrouille le CLI avec mot de passe
      password <mdp>         Modifie le mot de passe CLI/Telnet
      exit                   Ferme la session (reactive le verrou)
      loginWEB on/off        Active/desactive l'authentification de la page WEB
      login-passWEB <base64> Modifie le credential WEB (format Base64 user:pass)
      loginFTP <login>       Modifie le login FTP
      passwordFTP <mdp>      Modifie le mot de passe FTP

    CATEGORIE SERVICES :
      WEB on/off             Active/desactive le serveur WEB
      FTP on/off             Active/desactive le serveur FTP
      datalogger on/off      Active/desactive l'enregistrement CSV
      create <nom.ext>       Cree un fichier avec entete CSV
      select <nom.ext>       Selectionne le fichier datalogger actif

    CATEGORIE FICHIERS LittleFS (mini MS-DOS) :
      dir / ls               Liste les fichiers (taille, nom)
      type <fichier>         Affiche le contenu d'un fichier (CRLF auto pour Telnet)
      del <fichier>          Efface un fichier
      rename <old> <new>     Renomme un fichier (slash auto si absent)
      edit <texte>           Ajoute du texte dans le fichier en cours
      copie <src> <dst>      Copie un fichier (dst cree)
      format                 Formate la partition LittleFS (EFFACE TOUT)

    AUTOCOMPLETION ET HISTORIQUE :
      TAB                    Autocompletion de la commande
      Fleche Haut / Bas      Historique des commandes precedentes

  ---- 5.6  FONCTIONS UTILITAIRES (utils.h) ----

    Fonction               Entree              Sortie          Role
    --------------------   -----------------   -------------   -----------------------
    Boot_OK()              -                   Serial ANSI     Affiche [  OK  ] vert
    Boot_FAILED()          -                   Serial ANSI     Affiche [FAILED] rouge
    Boot_VIDE()            -                   Serial          Affiche [      ]
    PrintProgmem(p)        const char* PROGMEM cmdLine         Envoie texte PROGMEM
                                                               Convertit \n->\r\n
                                                               Convertit \033->ESC
    PremiereConnexionTelnet() clientTelnet     clientTelnet    Banner de bienvenue
                           premiereConnexion                   (1 seule fois)
    PremiereConnexionSerial() etatSerial       Serial          Banner reconnexion
    Datalogger()           conf.fichierEnCours LittleFS CSV    Enregistre date;heure;led
    DebugProg(text)        String text         /Log.txt        Log si debug==1
    PrintMAC(mac[6])       uint8_t[6]          cmdLine         Affiche MAC "XX:XX:..."
                                                               sprintf("%02X") zero-pad
                                                               garanti (cmdLine v24 OK
                                                               mais print(val,HEX) sans
                                                               zero-pad -> sprintf conserve)
    TestValidityIPadress   IPAddress x3        boolean         Verifie coherence
      (ip, subnet, gw)                                        IP/GW/masque

  ---- 5.7  GESTION DES ERREURS ----

    Situation                   Comportement
    --------------------------  ----------------------------------------------------
    LittleFS non monte          Boot_FAILED + FSok=0 + FTP desactive (pas de crash)
    WiFi echec 3 fois           Bascule en mode AP portail captif (10.0.0.1)
    Mode AP > 5 minutes         ESP.restart() automatique
    Ping passerelle echec       conf.nbrRebootperteWifi++ + EEPROM + ESP.restart()
    loop() bloquee > 1 min      Watchdog ISRwatchdog : ESP.restart()
    EEPROM invalide             default_conf chargee automatiquement
    IP incoherente              Bascule DHCP automatique au demarrage WiFi
    Authentification WEB echouee HTTP 401 (page refusee)
    Argument CLI manquant       "Operande absent : commande annulee" dans terminal
    Fichier LittleFS absent     Erreur affichee dans terminal (pas de crash)


=======================================================================================
  6. INTERFACES EXTERNES
=======================================================================================

  ---- 6.1  BIBLIOTHEQUES UTILISEES ----

    Bibliotheque          Version   Licence      Modifiee  Role dans le projet
    --------------------  --------  -----------  --------  --------------------------------
    ESP32 core (Espressif) 3.3.8   LGPL/Apache  Non       WiFi, LittleFS, EEPROM, BT, OTA
    Ticker                interne  LGPL          Non       Watchdog : ISR toutes les 1s
    EEPROM                interne  LGPL          Non       Persistance configuration
    WiFi                  interne  LGPL          Non       Connexion STA/AP, scan
    LittleFS              interne  LGPL          Non       Systeme de fichiers Flash
    DNSServer             interne  LGPL          Non       Portail captif (redirection DNS)
    ArduinoOTA            interne  LGPL          Non       Mise a jour firmware WiFi
    BluetoothSerial       interne  Apache        Non       Canal BT classique (Bluedroid)
    ESP32Ping             1.7      MIT           OUI       Ping ICMP + stats min/moy/max
    NTPClient             3.1.0    MIT           OUI       Synchronisation horloge NTP
    SimpleFTPServer       3.0.2    MIT           Non       Serveur FTP sur LittleFS
    CmdLine_Multiplatform v24      libre         OUI       Shell Serial/Telnet/BT

    MODIFICATIONS APPORTEES :
      ESP32Ping : ajout ping_get_min_time(), ping_get_max_time() dans ping.cpp/h
                  ajout minTime(), maxTime(), totalSent(), totalReceived() dans ESP32Ping
      NTPClient : getFormattedDateTime() JJ/MM/AAAA HH:MM:SS, getDayOfWeek() FR
      CmdLine v24 : support Telnet (updateNetwork), support Bluetooth (setBluetoothOutput)
                  historique fleches haut/bas, autocompletion TAB
                  write(uint8_t) correctement implemente sur les 3 canaux
                  print(val, HEX) fonctionnel sans crash (ambiguite vtable C++ resolue)

  ---- 6.2  PROTOCOLES RESEAU ----

    Protocole   Transport   Port(s)       Sens         Utilisation
    ----------  ----------  ------------  -----------  ------------------------------
    HTTP 1.1    TCP         80 (config.)  Entrant      Serveur WEB pages HTML + AJAX
    FTP (ctrl)  TCP         21            Entrant      Commandes FTP
    FTP (data)  TCP         50009 (PASV)  Entrant      Transfert fichiers
    Telnet      TCP         23            Entrant      Shell CLI reseau
    NTP         UDP         123           Sortant      Synchronisation horloge
    ICMP Echo   IP          -             Sortant      Ping supervision passerelle
    DNS (AP)    UDP         53            Entrant      Portail captif (redirect *)
    mDNS (OTA)  UDP         5353          Entrant      Decouverte OTA Arduino IDE
    Bluetooth   BT classique -            Bidirectionnel Shell CLI Bluetooth

  ---- 6.3  MATERIEL SUPPOSE PRESENT ----

    Materiel                  Connexion          Requis   Remarque
    ------------------------  -----------------  -------  ----------------------------
    WeMos D1 R32 (ESP32)      -                  OUI      Cible principale
    LED Grove rouge           D2 / GPIO26        OUI      Actionneur principal
    LED interne               GPIO2 (BUILTIN)    OUI      Indicateur de statut
    Grove Base Shield         empile sur D1 R32  NON      Facilite le cablage
    Routeur WiFi 2.4 GHz      infrastructure     OUI*     *Sauf mode AP
    PC avec Serial/Putty      USB / WiFi         NON      Configuration initiale

    ATTENTION ANTENNA :
    L'antenne 2.4 GHz est partagee entre WiFi et Bluetooth.
    Activer le Bluetooth (ENABLE_Bluetooth) degrade les performances WiFi
    et consomme ~70 KB de RAM supplementaire (Bluedroid stack).
    --> Recommande : garder Bluetooth desactive (//#define ENABLE_Bluetooth)


=======================================================================================
  7. CONTRAINTES NON FONCTIONNELLES
=======================================================================================

  ---- 7.1  TIMING / TEMPS REEL ----

    Contrainte                Valeur          Source
    ------------------------  --------------  -----------------------------------
    Frequence CPU             240 MHz         ESP32 WROOM-32 (Xtensa LX6)
    Periode loop nominale     < 50 ms         Sans blocage client WEB/FTP
    Periode loop max tolere   60 000 ms       Watchdog : reboot au-dela
    Duree max blocage loop    1 min = 60 s    Watchdog ISRwatchdog (Ticker 1 Hz)
    Timeout serveur WEB       5 s             previousMillisWEB (5 x 1000 ms)
    Clignotement LED STA      1 000 ms        previousMillisCoeur
    Clignotement LED AP       100 ms          previousMillisCoeur (10 Hz)
    Timer mode AP max         5 min (300 s)   DUREE_MODE_AP_MS
    Periode ping supervision  10 min          10UL*60UL*1000UL ms
    1er ping apres boot       30 s            previousMillisPing init = -(10min-30s)
    Mise a jour NTP           60 000 ms       setUpdateInterval NTPClient
    Decalage horaire NTP      UTC+1 (3600 s)  NTPClient offset
    Timeout connexion WiFi    10 s (20 iter)  cmpt == 2*10 dans Wifi_ESP_START

    NOTE : le systeme est cooperatif. Un client WEB ou FTP actif peut bloquer
    les autres taches pendant la duree du transfert. Le watchdog protege
    contre un blocage indefini.

  ---- 7.2  MEMOIRE ----

    Ressource              Valeur          Remarque
    --------------------   --------------  ------------------------------------------
    Flash totale           4 MB            ESP32 WROOM-32
    Firmware (code+data)   ~1.08 MB (82%)  Partition "No OTA" 1.31 MB max
    LittleFS disponible    1.375 a 1.875 MB Selon partition choisie
    EEPROM virtuelle       512 octets      Allouee au boot (EEPROM.begin(512))
    RAM totale             520 KB SRAM     ESP32 (dont ~327 KB accessible app)
    RAM globales           ~57.5 KB (17%)  Variables globales + conf_t
    RAM disponible         ~270 KB (83%)   Sans Bluetooth
    RAM disponible BT ON   ~198 KB         Bluedroid consume ~70 KB
    Buffer HTTP            1024 octets     REQ_BUF_SZ (requetes GET/POST)
    Buffer PrintProgmem    256 octets      Envoi PROGMEM par blocs
    Stack watchdog         minimal         ISR Ticker (pas de malloc)

    RECOMMANDATIONS MEMOIRE :
    - Surveiller ESP.getFreeHeap() avec la commande "ram" si ajout de services.
    - Ne pas activer Bluetooth et OTA simultanement (pression memoire forte).
    - LittleFS.begin(false) : ne jamais passer true en production
      (formate TOUT si montage echoue -- perte de donnees).

  ---- 7.3  FLASH / ESPACE DISQUE ----

    Partition LittleFS recommandee (1.375 MB pour "Default 4MB") :

    Fichier                  Taille typique   Remarque
    -----------------------  ---------------  ----------------------------------
    /index.html              ~15 KB           Page WEB commande LED
    /ConfIP_SSID_JS.html     ~20 KB           Page WEB configuration reseau
    /datalogger.csv          variable         ~60 octets par entree
    /Log.txt                 variable         ~50 octets par entree debug

    Espace libre minimal recommande : 100 KB (marge securite LittleFS).

  ---- 7.4  CONSOMMATION ENERGETIQUE ----

    Mode                    Courant typique   Remarque
    ----------------------  ---------------   --------------------------------
    WiFi STA actif          ~80-150 mA        Selon trafic reseau
    WiFi AP (portail)       ~80-120 mA        Moins de trafic
    WiFi OFF (CLI serial)   ~30-50 mA         Sans radio active
    Bluetooth actif         +50-100 mA        Bluedroid stack actif

    Alimentation requise : 3.3 V, minimum 500 mA (recommande : 1 A sur USB)
    La tension VCC est mesuree au boot via rom_phy_get_vdd33() (typique 3.3 V).


=======================================================================================
  8. LICENCE
=======================================================================================

  LICENCE CHOISIE : GNU Lesser General Public License v2.1 (LGPL v2.1)
  URL             : https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html

  RAISON DU CHOIX :
    La licence LGPL v2.1 a ete choisie pour sa compatibilite avec l'ecosysteme
    Arduino/Espressif (core ESP32 sous LGPL/Apache) et pour permettre l'integration
    dans des projets commerciaux sans imposer la publication de l'ensemble du code
    applicatif de l'utilisateur.

    Compatibilite avec les bibliotheques tierces :
      MIT (NTPClient, SimpleFTPServer, ESP32Ping) : compatible LGPL
      LGPL v2.1 (ESP32 core, Ticker, LittleFS) : meme licence, compatible
      CmdLine (libre) : compatible

  DROITS ACCORDES (code IoToS) :
    - Usage libre, y compris commercial
    - Modification des fichiers IoToS
    - Integration dans un firmware proprietaire
    - Le code applicatif (.ino) reste la propriete de l'auteur final

  OBLIGATIONS (redistribution uniquement) :
    - Distribuer les sources IoToS modifiees avec les modifications
    - Conserver les en-tetes de copyright dans les fichiers
    - Mentionner l'usage d'IoToS et sa licence dans la documentation
    - Ne pas ajouter de restrictions supplementaires sur IoToS

  GARANTIE :
    FOURNI EN L'ETAT SANS GARANTIE.
    L'AUTEUR N'EST PAS RESPONSABLE DES DOMMAGES RESULTANT DE L'USAGE.

  CODE APPLICATIF :
    Le fichier .ino et les adaptations specifiques au projet
    restent la propriete de Jean-Marc Biechy / Institution Saint-Jean.
    Utilisation pedagogique libre dans le cadre de l'etablissement.


=======================================================================================
  ANNEXE A -- TABLEAU DE BORD RAPIDE
=======================================================================================

  Acces                  Adresse                  Identifiants par defaut
  --------------------   ----------------------   ------------------------------
  Page WEB               http://192.168.0.11/     user:pass (si loginWEB active)
  Configuration IP WEB   http://192.168.0.11/ConfIP_SSID_JS.html
  Portail Captif AP      http://10.0.0.1/         (pas d'auth)
  Telnet CLI             192.168.0.11 port 23     changerLeMotDePasse (si login ON)
  FTP FileZilla          192.168.0.11 port 21     esp32 / esp32
  Serial                 115200 bauds 8N1         (pas d'auth -- "stop" dans 3s)
  Bluetooth              "ESP32" (nom systeme)    (pas d'auth -- si ENABLE_Bluetooth)


=======================================================================================
  ANNEXE B -- COMMANDES DE PREMIERE CONFIGURATION
=======================================================================================

  Apres le premier flash, taper "stop" dans les 3 secondes, puis :

  > SSID MonReseauWiFi
  > wifipass MonMotDePasse
  > ip 192.168.1.100
  > subnet 255.255.255.0
  > gateway 192.168.1.1
  > save
  > reset

  Verifier la connexion :
  > print
  > ping 8.8.8.8

  Activer le datalogger :
  > create /log2026.csv
  > select /log2026.csv
  > datalogger on
  > save


=======================================================================================
  ANNEXE C -- POINTS D'ATTENTION ET PIEGES CONNUS
=======================================================================================

  +---+------------------------------------+--------------------------------------+
  | # | Piege                              | Solution                             |
  +---+------------------------------------+--------------------------------------+
  | 1 | VALID EEPROM (1000043 vs 1000271)  | Verifier #define VALID dans .ino     |
  |   | Valeur peut etre obsolete          | avant flash -- pilote validite EEPROM|
  +---+------------------------------------+--------------------------------------+
  | 2 | LittleFS.begin(true)               | Toujours utiliser begin(false)       |
  |   | formate TOUT si montage echoue     | en production                        |
  +---+------------------------------------+--------------------------------------+
  | 3 | mklittlefs != mkspiffs             | Ne pas utiliser mkspiffs -- formats  |
  |   | formats binaires incompatibles     | incompatibles -> LittleFS vide       |
  +---+------------------------------------+--------------------------------------+
  | 4 | LittleFS.open(dir) sans flag "r"   | Toujours open("/", "r") pour les     |
  |   | -> abort() dans openNextFile()     | repertoires (core ESP32 3.x)         |
  +---+------------------------------------+--------------------------------------+
  | 5 | entry.name() retourne chemin full  | Extraire le nom seul : chercher '/'  |
  |   | ex: "/fichier.html" (core 3.x)     | et prendre la partie apres           |
  +---+------------------------------------+--------------------------------------+
  | 6 | Bluetooth actif + WiFi             | Garder //#define ENABLE_Bluetooth    |
  |   | -> contention antenne + 70KB RAM   | sauf besoin explicite                |
  +---+------------------------------------+--------------------------------------+
  | 7 | cmdLine.print(val, HEX) MAC        | sprintf("%02X") CONSERVE meme en     |
  |   | pas de zero-padding ("A" vs "0A")  | CmdLine v24 -- zero-pad obligatoire  |
  +---+------------------------------------+--------------------------------------+
  | 8 | Serial.println() dans SetMac()     | Corrige en v74 : cmdLine.println()   |
  |   | -> rien affiche sur Telnet         | sur les 3 canaux                     |
  +---+------------------------------------+--------------------------------------+
  | 9 | WiFi.macAddress() apres            | delay(200) apres WiFi.mode(WIFI_STA) |
  |   | WiFi.mode() -> 00:00:00 retourne   | avant WiFi.macAddress()              |
  +---+------------------------------------+--------------------------------------+
  |10 | Buffer HTTP_req trop petit         | REQ_BUF_SZ = 1024 (double depuis     |
  |   | -> troncature longues URL GET/POST | v70.1 -- ne pas reduire)             |
  +---+------------------------------------+--------------------------------------+
  |11 | strtok() sur HTTP_req              | Remplace par strstr()+atoi() directs |
  |   | -> insere '\0' -> strstr echoue    | HTTP_req non modifie (v70.1)         |
  +---+------------------------------------+--------------------------------------+


=======================================================================================
  ANNEXE D -- HISTORIQUE COMPLET DES VERSIONS
=======================================================================================

  (du plus ancien au plus recent -- version courante en dernier)

  +-------+--------------------------------------------------------------------+
  | v73a  | Desactivation conditionnelle NTP (#ifdef ENABLE_NTP)               |
  |       | NTP provoquait des instabilites avec LittleFS et WiFi              |
  |       | Code NTP conserve intact pour reactivation par #define             |
  +-------+--------------------------------------------------------------------+
  | v73b  | Diagnostic instabilite -- desactivation Bluetooth                  |
  |       | Cause racine identifiee : Bluedroid ~70 KB RAM + contention        |
  |       | antenne 2.4 GHz + contention bus SPI Flash avec LittleFS           |
  |       | #define ENABLE_Bluetooth conditionne la compilation BT             |
  |       | RAM liberee : ~198 KB libres (vs ~128 KB avec BT)                  |
  +-------+--------------------------------------------------------------------+
  | v73c  | Bug mode AP corrige (break apres WiFiModeAP)                       |
  |       | Sans break : boucle while infinie "......." car WiFi.status()      |
  |       | != WL_CONNECTED toujours vrai en mode AP                           |
  |       | Slash auto sur rename/type : '/' ajoute si absent                  |
  +-------+--------------------------------------------------------------------+
  | v73d  | Correction MAC 00:00:00:00:00:00                                   |
  |       | Cause : WiFi.macAddress() appele avant esp_wifi_start()            |
  |       | Correction : delay(200) apres WiFi.mode(WIFI_STA)                  |
  |       | Conversion CRLF affichage fichiers Telnet (\n -> \r\n dans Type()) |
  +-------+--------------------------------------------------------------------+
  | v73e  | Correction FTP liste vide                                          |
  |       | Cause : #include "LittleFS.h" (guillemets) au lieu de              |
  |       | #include <LittleFS.h> (chevrons) -> mauvaise resolution include    |
  +-------+--------------------------------------------------------------------+
  | v73f  | Ajout OTA conditionnel (#ifdef ENABLE_OTA)                         |
  |       | OTA desactivable sans modifier le code fonctionnel                 |
  |       | Libere RAM et Flash si non utilise                                 |
  +-------+--------------------------------------------------------------------+
  | v73g  | Tache Ping passerelle dans loop() (toutes les 10 min)              |
  |       | Statistiques ping min/moy/max style Windows                        |
  |       | Reboot automatique si passerelle injoignable                       |
  |       | Compteur nbrRebootperteWifi en EEPROM                              |
  |       | Modification de VALID pour invalider l'ancienne EEPROM             |
  +-------+--------------------------------------------------------------------+
  | v73h  | Suppression gardes #ifdef ENABLE_NTP (NTP toujours actif)          |
  |       | Correction MAC custom : SetMacCustom() corrige                     |
  |       | PrintMAC() : fonction utilitaire centralisee dans utils.h          |
  +-------+--------------------------------------------------------------------+
  | v73i  | Archive intermediaire (renommee -- ne pas utiliser)                |
  +-------+--------------------------------------------------------------------+
  | v73j  | Archive intermediaire (renommee -- ne pas utiliser)                |
  +-------+--------------------------------------------------------------------+
  | v74   | Version finale : correction cosmetique globale                     |
  |       | - Suppression de tous les accents dans les commentaires            |
  |       | - Correction orthographe (30+ fautes : Autentification, healder,   |
  |       |   LED_BUELDING->LED_BUILTIN, ESP38->ESP32, Bluethoots, etc.)       |
  |       | - Suppression des marqueurs FIX inline dans le corps du code       |
  |       | - Ajout bloc historique versions v73a->v74 en fin de .ino          |
  |       | - Ancien nom Shell_CmdLine_SPIFFS_WiFi.h corrige en LittleFS       |
  |       | - Aucune modification fonctionnelle                                |
  +-------+--------------------------------------------------------------------+
  | v74   | Correction SetMac() + mise a jour commentaires CmdLine v24         |
  | (*)   | BUG CORRIGE : Serial.println() -> cmdLine.println() dans SetMac()  |
  |       |   Telnet n'affichait pas la nouvelle MAC apres commande "mac"      |
  |       | Commentaires MAC mis a jour (3 boucles : PrintMAC, PrintConf,      |
  |       |   SetMacCustom) : suppression ref "bug connu v72", ajout note v24  |
  |       | sprintf("%02X") CONSERVE dans les 3 boucles MAC :                  |
  |       |   print(val,HEX) OK en v24 mais sans zero-padding -> "A" pas "0A"  |
  |       |   sprintf garantit le format "0A" obligatoire pour les MAC         |
  |       | Fichiers modifies : utils.h (old1), Shell_CmdLine_LittleFS_WiFi.h  |
  |       |   (old2 PrintConf, old3 SetMacCustom, old4 SetMac BUG CORRIGE)     |
  +-------+--------------------------------------------------------------------+
  (*) Version courante -- fichiers actifs dans le projet

  RESUME MODIFICATIONS v74 -- DETAIL PAR FICHIER :

    utils.h -- old1 :
      PrintMAC() : commentaire mis a jour
        - Suppression "bug connu v72 / non supporte par lib CmdLine"
        - Ajout note CmdLine v24 : print(val,HEX) OK mais sans zero-pad
        - Justification sprintf("%02X") conserve
        Code : INCHANGE

    Shell_CmdLine_LittleFS_WiFi.h -- old2 :
      PrintConf() boucle MAC conf_TMP : commentaire mis a jour
        - Suppression "Probleme resolu v72 fix / non supporte..."
        - Remplacement par "Note CmdLine v24"
        Code : INCHANGE

    Shell_CmdLine_LittleFS_WiFi.h -- old3 :
      SetMacCustom() boucle MAC conf.mac : commentaire mis a jour
        - Suppression "Meme bug que dans PrintConf / non supporte..."
        - Remplacement par "Note CmdLine v24"
        Code : INCHANGE

    Shell_CmdLine_LittleFS_WiFi.h -- old4 :
      SetMac() : BUG CORRIGE -- 1 ligne modifiee
        AVANT : Serial.println(WiFi.macAddress())
                --> Telnet : rien affiche
        APRES : cmdLine.println(WiFi.macAddress())
                --> Serial + Telnet + Bluetooth


=======================================================================================
  ANNEXE E -- ETAT DES FONCTIONNALITES CONDITIONNELLES
=======================================================================================

  Fonctionnalite    Define               Etat par defaut   Impact si active
  ----------------  -------------------  ----------------  -------------------------
  Bluetooth         ENABLE_Bluetooth     DESACTIVE (//)    +70 KB RAM, contention HF
  OTA               ENABLE_OTA           A configurer      +RAM OTA stack
  NTP               (toujours actif)     ACTIF             Necessite connexion STA

  Pour activer Bluetooth :
    1. Retirer le commentaire : #define ENABLE_Bluetooth
    2. Choisir un scheme de partition sans OTA (plus de RAM APP)
    3. Verifier ESP.getFreeHeap() > 150 KB apres boot
    4. Ne pas activer simultanément BT + OTA

  Pour activer OTA :
    1. Retirer le commentaire : #define ENABLE_OTA
    2. Choisir un scheme de partition avec OTA (Default 4MB ou Minimal SPIFFS)
    3. Dans Arduino IDE : Croquis --> Transferer par OTA

  Pour desactiver NTP (si instabilite) :
    NTP est desormais toujours compile (gardes #ifdef supprimes en v73h).
    Pour le desactiver, commenter l'appel timeClient.update() dans loop()
    et timeClient.begin() dans setup().


=======================================================================================
  ANNEXE F -- ANALYSE SURCHARGES BOUCLES MAC (CmdLine v24)
=======================================================================================

  Trois boucles affichent une adresse MAC octet par octet dans le projet :

    Fonction         Fichier                          Variable
    ---------------  -------------------------------  ----------------
    PrintMAC()       utils.h                          mac[i]
    PrintConf()      Shell_CmdLine_LittleFS_WiFi.h    conf_TMP.mac[i]
    SetMacCustom()   Shell_CmdLine_LittleFS_WiFi.h    conf.mac[i]

  Chacune utilise :
      sprintf(hexByte, "%02X", mac[i]);
      cmdLine.print(hexByte);

  Question : peut-on simplifier en cmdLine.print(mac[i], HEX) ?

  REPONSE : NON -- le sprintf est NECESSAIRE.

    Comparaison :
      cmdLine.print(0x0A, HEX) --> affiche "A"   (pas de zero-padding)
      sprintf("%02X", 0x0A)    --> produit "0A"  (zero-padding garanti)

    Une adresse MAC s'affiche TOUJOURS avec zero-padding :
      CORRECT   : "08:AB:CD:EF:01:23"
      INCORRECT : "8:AB:CD:EF:1:23"   (sans zero-padding sur les octets < 0x10)

  Conclusion : sprintf("%02X") est conserve dans les 3 boucles.
               Le code fonctionnel est INCHANGE. Seuls les commentaires sont mis a jour.

  Boucle MAC au boot (Driver_ESP32_Reseau_PortailCaptif.h -- Wifi_ESP_START) :
    Utilise Serial.print(macPhys[i], HEX) avec zero-padding manuel.
    Normal : cmdLine n'est pas initialise au boot.
    --> Aucune modification necessaire.


=======================================================================================
  FIN DOCUMENT -- v74 -- 20/05/2026
=======================================================================================
