Comment scanner des codes QR en utilisant le module ESP32-CAM

ESP32CAM QR Code Scanner Project

Génération de la clé API

Nous avons besoin d’une clé API pour utiliser l’API du scanner de codes QR. Vous pouvez l’obtenir sur raspberryme.cloud. Suivez les étapes ci-dessous pour obtenir votre propre clé API.

Connexion au compte Circuit Digest Cloud

ÉTAPE 1 : Visitez le site Circuit Digest Cloud à raspberryme.cloud. Cliquez sur le bouton « Connexion » situé en haut à droite pour être redirigé vers la page de connexion.

ÉTAPE 2 : Si vous avez déjà un compte, connectez-vous en utilisant vos identifiants existants. Sinon, rendez-vous sur la page d’inscription pour créer un compte en remplissant les détails requis. Une fois terminé, cliquez sur « S’inscrire maintenant » pour vous inscrire.

ÉTAPE 3 : Après l’inscription, utilisez votre ID e-mail et votre mot de passe pour vous connecter sur la page de connexion.

Processus de génération de la clé API

ÉTAPE 4 : Une fois connecté, cliquez sur « Mon compte » en haut à droite.

ÉTAPE 5 : Vous serez dirigé vers une page où vous pouvez générer votre clé API. Entrez le texte CAPTCHA dans la case fournie, puis cliquez sur le bouton « Soumettre ».

ÉTAPE 6 : Si le CAPTCHA est correct, vous verrez un tableau affichant votre clé API ainsi que sa date d’expiration et le nombre d’utilisations. Actuellement, il y a une limite de 50 utilisations par clé. Une fois que vous atteignez cette limite, vous pouvez générer une autre clé, vous donnant 50 utilisations supplémentaires. Cette limite d’utilisation est en place pour éviter une surcharge du serveur.

Pour plus de détails concernant la clé API, la validité de l’accès API, consultez notre autre blog qui explique l’API du scanner de codes QR pour les cartes SoC embarquées à faible consommation d’énergie.

À cette étape, vous devriez avoir obtenu votre clé API, utilisons cette clé dans notre code.

Comment scanner des codes QR en utilisant le module ESP32 CAM1724281379 730 Comment scanner des codes QR en utilisant le module ESP32 CAM

Code

#include
#include
#include
#include « soc/soc.h »
#include « soc/rtc_cntl_reg.h »
#include « esp_camera.h »

// Inclus des I2C et de l’affichage OLED
#include
#include
#include

// L’ESP32-CAM n’a pas de broches I2C dédiées, nous définissons donc les nôtres
#define I2C_SDA 15
#define I2C_SCL 14
TwoWire I2Cbus = TwoWire(0);

// Définitions de l’affichage
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &I2Cbus, OLED_RESET);

const char* ssid = « xxx »;         // Remplacez « xxx » par votre SSID WiFi
const char* password = « xxx »;      // Remplacez « xxx » par votre mot de passe WiFi
String serverName = « www.raspberryme.cloud« ;  // Domaine du serveur
String serverPath = « /readqrcode »;              // Chemin de l’API
const int serverPort = 443;                     // Port HTTPS
String apiKey = « xxx »;             // Remplacez « xxx » par votre clé API

#define triggerButton 13  // Broche GPIO pour le bouton de déclenchement
#define flashLight 4      // Broche GPIO pour la lumière de poche
int count = 0;           // Compteur pour les téléchargements d’images

WiFiClientSecure client; // Client sécurisé pour la communication HTTPS

// Pins GPIO de la caméra – ajustez en fonction de votre carte ESP32-CAM
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22

 

// Fonction pour extraire une valeur de tableau JSON par clé
String extractJsonArrayValue(const String& jsonString, const String& key) {
  int keyIndex = jsonString.indexOf(key);
  if (keyIndex == -1) {
    return «  »;
  }

  int startIndex = jsonString.indexOf(‘[‘, keyIndex);
  int endIndex = jsonString.indexOf(‘]’, startIndex);

  if (startIndex == -1 || endIndex == -1) {
    return «  »;
  }

  return jsonString.substring(startIndex, endIndex + 1);
}

// Fonction pour extraire une valeur de chaîne JSON par clé
String extractJsonStringValue(const String& jsonString, const String& key) {
  int keyIndex = jsonString.indexOf(key);
  if (keyIndex == -1) {
    return «  »;
  }

  int startIndex = jsonString.indexOf(‘:’, keyIndex) + 2;
  int endIndex = jsonString.indexOf(‘ »‘, startIndex);

  if (startIndex == -1 || endIndex == -1) {
    return «  »;
  }

  return jsonString.substring(startIndex, endIndex);
}

// Fonction pour afficher du texte sur OLED
void displayText(String text) {
  display.clearDisplay();
  display.setCursor(0, 10);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.print(text);
  display.display();
}

void setup() {
  // Désactiver le détecteur de sous-tension
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  Serial.begin(115200);
  pinMode(flashLight, OUTPUT);
  pinMode(triggerButton, INPUT);
  digitalWrite(flashLight, LOW);

  // Connexion au WiFi
  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print(« Connexion à « );
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(« . »);
    delay(500);
  }
  Serial.println();
  Serial.print(« Adresse IP ESP32-CAM : « );
  Serial.println(WiFi.localIP());

  // Configurer la caméra
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  // Ajuster la taille et la qualité de l’image en fonction de la disponibilité du PSRAM
  if (psramFound()) {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 5;  // Un nombre plus bas signifie une qualité plus élevée (0-63)
    config.fb_count = 2;
    Serial.println(« PSRAM trouvé »);
  } else {
    config.frame_size = FRAMESIZE_CIF;
    config.jpeg_quality = 12;  // Un nombre plus bas signifie une qualité plus élevée (0-63)
    config.fb_count = 1;
  }

  // Initialiser la caméra
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf(« Échec de l’initialisation de la caméra avec l’erreur 0x%x », err);
    delay(1000);
    ESP.restart();
  }

  // Initialiser l’I2C avec nos broches définies
  I2Cbus.begin(I2C_SDA, I2C_SCL, 100000);

  // Initialiser l’affichage OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.printf(« Échec de l’initialisation de l’affichage OLED SSD1306.\nVérifiez que le SDA de l’affichage est connecté à la broche %d et que le SCL est connecté à la broche %d\n », I2C_SDA, I2C_SCL);
    while (true);
  }

  // Afficher les messages d’initialisation
  displayText(« Initialisation du système réussie »);
  delay(1000);
  displayText(« Appuyez sur le bouton de déclenchement \n\npour commencer la capture »);
}

 

void loop() {
  // Vérifier si le bouton de déclenchement est enfoncé
  if (digitalRead(triggerButton) == HIGH) {
    int status = sendPhoto();
    if (status == -1) {
      displayText(« Échec de la capture d’image »);
    } else if (status == -2) {
      displayText(« Échec de la connexion au serveur »);
    }
  }
}

// Fonction pour capturer et envoyer une photo au serveur
int sendPhoto() {
  camera_fb_t* fb = NULL;
 
  // Allumer la lumière de poche et capturer l’image
  digitalWrite(flashLight, HIGH);
  delay(1000);
  fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println(« Échec de la capture de la caméra »);
    return -1;
  }
 
  // Afficher le message de succès
  displayText(« Capture d’image réussie »);
  delay(300);
  digitalWrite(flashLight, LOW);

  // Connexion au serveur
  Serial.println(« Connexion au serveur: » + serverName);
  displayText(« Connexion au serveur:\n\n » + serverName);
  client.setInsecure();  // Ignorer la validation du certificat pour simplifier

  if (client.connect(serverName.c_str(), serverPort)) {
    Serial.println(« Connexion réussie ! »);
    displayText(« Connexion réussie ! »);
    delay(300);
    displayText(« Téléchargement des données ! »);
   
    // Incrémenter le compteur et préparer le nom du fichier
    count++;
    Serial.println(count);
    String filename = apiKey + « .jpeg »;

    // Préparer la requête HTTP POST
    String head = « –CircuitDigest\r\nContent-Disposition: form-data; name=\ »imageFile\ »; filename=\ » » + filename + « \ »\r\nContent-Type: image/jpeg\r\n\r\n »;
    String tail = « \r\n–CircuitDigest–\r\n »;
    uint32_t imageLen = fb->len;
    uint32_t extraLen = head.length() + tail.length();
    uint32_t totalLen = imageLen + extraLen;

    client.println(« POST  » + serverPath +  » HTTP/1.1″);
    client.println(« Host:  » + serverName);
    client.println(« Content-Length:  » + String(totalLen));
    client.println(« Content-Type: multipart/form-data; boundary=CircuitDigest »);
    client.println(« Authorization: » + apiKey);
    client.println();
    client.print(head);

    // Envoyer les données de l’image par morceaux
    uint8_t* fbBuf = fb->buf;
    size_t fbLen = fb->len;
    for (size_t n = 0; n < fbLen; n += 1024) {
      if (n + 1024 < fbLen) {
        client.write(fbBuf, 1024);
        fbBuf += 1024;
      } else {
        size_t remainder = fbLen % 1024;
        client.write(fbBuf, remainder);
      }
    }

    client.print(tail);

    // Nettoyer
    esp_camera_fb_return(fb);
    displayText(« En attente de réponse ! »);

    // Attendre la réponse du serveur
    String response;
    long startTime = millis();
    while (client.connected() && millis() – startTime < 10000) {
      if (client.available()) {
        char c = client.read();
        response += c;
      }
    }

    // Extraire et afficher les données du code QR de la réponse
    String qrCodeData = extractJsonArrayValue(response, « \ »QR_code\ » »);
    String imageLink = extractJsonStringValue(response, « \ »view_image\ » »);

    Serial.print(« Données QR : « );
    Serial.println(qrCodeData);

    Serial.print(« ImageLink : « );
    Serial.println(imageLink);

    displayText(« Données du code QR:\n\n » + qrCodeData);

    client.stop();
    return 0;
  } else {
    Serial.println(« Échec de la connexion au serveur »);
    return -2;
  }
}

Retrouvez l’histoire de Raspberry Pi dans cette vidéo :

YouTube video

  • EIAOSI GM60 UART Module scanner de codes-barres 1D/QR/2D en acier inoxydable avec affichage annulaire QR Code
  • Eyoyo Lecteur Codes Barres 1D 2D, Handheld Wired USB douchette Code Barre QR PDF417 Data Matrix Barcode Scanner with USB Cable for PC Mac pour Mobile Payment, Convenience Store…