Tutorial del Internet de las Cosas y Bluetooth con el ESP32
Juan Antonio Villalpando
Volver al índice del tutorial
____________________________
247B.- ESP32-CAM WiFi con OV2640. Lector de QR.
- Este tutorial es una continuación del 247_WemosCam.htm , en esta ocasión vamos a leer un código QR con la Cámara y visualizar su decodificacion en el Monitor Serie.
- Seguiremos este tutorial: https://www.youtube.com/watch?v=tZV7b8dGgw4
- Como habrás observado, no tiene conector USB para introducirle el programa, así que también necesitaremos un FTDI FT232RL USB, unos 2 €
- Observa el tipo de conector USB que utiliza este módulo, es un Mini-B USB.
|
Cable necesario para conectar este módulo al ordenador. |
________________________________________________
1.- Lectura de QR y visualización en el Monitor Serie.
- Establecemos la Placa: "AI Thinker ESP32-CAM"
- Cargamos la librería quirc_lib.zip
- Cargamos el código:
|
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "quirc.h"
// creating a task handle
TaskHandle_t QRCodeReader_Task;
/* GPIO of CAMERA_MODEL_AI_THINKER */
#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
/* Variables declaration */
struct QRCodeData
{
bool valid;
int dataType;
uint8_t payload[1024];
int payloadLen;
};
struct quirc *q = NULL;
uint8_t *image = NULL;
camera_fb_t * fb = NULL;
struct quirc_code code;
struct quirc_data data;
quirc_decode_error_t err;
struct QRCodeData qrCodeData;
String QRCodeResult = "";
/* VOID SETTUP() */
void setup() {
// Disable brownout detector.
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
/* Init serial communication speed (baud rate). */
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
/* Camera configuration. */
Serial.println("Start configuring and initializing the camera...");
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 = 10000000;
config.pixel_format = PIXFORMAT_GRAYSCALE;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 15;
config.fb_count = 1;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA);
Serial.println("Configure and initialize the camera successfully.");
Serial.println();
/* Create "QRCodeReader_Task" using the xTaskCreatePinnedToCore() function */
xTaskCreatePinnedToCore(
QRCodeReader, /* Task function. */
"QRCodeReader_Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&QRCodeReader_Task, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
}
void loop() {
// put your main code here, to run repeatedly:
delay(1);
}
/* The function to be executed by "QRCodeReader_Task" */
// This function is to instruct the camera to take or capture a QR Code image,
// then it is processed and translated into text.
void QRCodeReader( void * pvParameters ){
Serial.println("QRCodeReader is ready.");
Serial.print("QRCodeReader running on core ");
Serial.println(xPortGetCoreID());
Serial.println();
/* Loop to read QR Code in real time. */
while(1){
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
fb = esp_camera_fb_get();
if (!fb)
{
Serial.println("Camera capture failed");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
Serial.println("Decoding FAILED");
QRCodeResult = "Decoding FAILED";
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
esp_camera_fb_return(fb);
fb = NULL;
image = NULL;
quirc_destroy(q);
}
}
/* Function to display the results of reading the QR Code on the serial monitor. */
void dumpData(const struct quirc_data *data)
{
Serial.printf("Version: %d\n", data->version);
Serial.printf("ECC level: %c\n", "MLHQ"[data->ecc_level]);
Serial.printf("Mask: %d\n", data->mask);
Serial.printf("Length: %d\n", data->payload_len);
Serial.printf("Payload: %s\n", data->payload);
QRCodeResult = (const char *)data->payload;
}
|
- Conectamos el FTDI al ESP32-CAM para cargar el código.
- [Cada vez que vayamos a cargar un programa es conveniente quitar el cable USB y volver a ponerlo].
- [Cada vez que vayamos a cargar un programa debemos conectar el cable GND y IO0].
- Cuando haya terminado de cargar, quitamos el cable gris que conecta al GND y IO0.
- Abrimos el Monitor Serie, lo establecemos en 115200 baudios.
- Escaneamos un QR, debe ser de gran dimensión por ejemplo de 5x5 cm. Podemos fotografiar QR con nuestro móvil y escanear esa foto de nuestro móvil.
- Ponemos la ESP32-CAM a unos 15 cm de distancia, si el QR tiene unas dimensiones de 5x5 cm.
- Mediante esta página generamos un QR: https://www.the-qrcode-generator.com/
__________________________________________________________________
- Aquí tenemos otro modelo similar con el ESP32-S WiFi y la cam OV2640.
- Lo bueno que tiene este modelo es que contiene el conector para el cable USB, es decir no necesitamos la tarjeta FTDI del modelo anterior.
- También podemos encontrar otros modelos de FTDI en donde el conector USB tiene otras dimensiones:
_____________________________________________
- Otros enlaces.
- Otro tutorial: https://www.youtube.com/watch?v=Lb88kd4js0E
__________________________________________________________
2.- Lee QR y enciende/apaga dos LEDs.
- Conectamos dos LED al módulo ESP32-CAM, como indica la imagen:
- Generamos 4 QR con estos datos:
LED BLUE ON
LED BLUE OFF
LED GREEN ON
LED GREEN OFF
- Según lea uno de esos 4 QR, se encenderá o apagará el LED correspondiente.
- Añadimos este código:
/* Additional code to control the LED.
#define LED_Green 12
#define LED_Blue 13
...
pinMode(LED_Blue, OUTPUT);
pinMode(LED_Green, OUTPUT);
...
if (QRCodeResult == "LED BLUE ON") digitalWrite(LED_Blue, HIGH);
if (QRCodeResult == "LED BLUE OFF") digitalWrite(LED_Blue, LOW);
if (QRCodeResult == "LED GREEN ON") digitalWrite(LED_Green, HIGH);
if (QRCodeResult == "LED GREEN OFF") digitalWrite(LED_Green, LOW);
*/
- Aquí lo tenemos añadido:
|
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "quirc.h"
// creating a task handle
TaskHandle_t QRCodeReader_Task;
/* GPIO of CAMERA_MODEL_AI_THINKER */
#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
#define LED_Green 12
#define LED_Blue 13
/* Variables declaration */
struct QRCodeData
{
bool valid;
int dataType;
uint8_t payload[1024];
int payloadLen;
};
struct quirc *q = NULL;
uint8_t *image = NULL;
camera_fb_t * fb = NULL;
struct quirc_code code;
struct quirc_data data;
quirc_decode_error_t err;
struct QRCodeData qrCodeData;
String QRCodeResult = "";
/* VOID SETTUP() */
void setup() {
// Disable brownout detector.
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
/* Init serial communication speed (baud rate). */
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
pinMode(LED_Blue, OUTPUT);
pinMode(LED_Green, OUTPUT);
/* Camera configuration. */
Serial.println("Start configuring and initializing the camera...");
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 = 10000000;
config.pixel_format = PIXFORMAT_GRAYSCALE;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 15;
config.fb_count = 1;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA);
Serial.println("Configure and initialize the camera successfully.");
Serial.println();
/* Create "QRCodeReader_Task" using the xTaskCreatePinnedToCore() function */
xTaskCreatePinnedToCore(
QRCodeReader, /* Task function. */
"QRCodeReader_Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&QRCodeReader_Task, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
}
void loop() {
if (QRCodeResult == "LED BLUE ON") digitalWrite(LED_Blue, HIGH);
if (QRCodeResult == "LED BLUE OFF") digitalWrite(LED_Blue, LOW);
if (QRCodeResult == "LED GREEN ON") digitalWrite(LED_Green, HIGH);
if (QRCodeResult == "LED GREEN OFF") digitalWrite(LED_Green, LOW);
// put your main code here, to run repeatedly:
delay(1);
}
/* The function to be executed by "QRCodeReader_Task" */
// This function is to instruct the camera to take or capture a QR Code image,
// then it is processed and translated into text.
void QRCodeReader( void * pvParameters ){
Serial.println("QRCodeReader is ready.");
Serial.print("QRCodeReader running on core ");
Serial.println(xPortGetCoreID());
Serial.println();
/* Loop to read QR Code in real time. */
while(1){
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
fb = esp_camera_fb_get();
if (!fb)
{
Serial.println("Camera capture failed");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
Serial.println("Decoding FAILED");
QRCodeResult = "Decoding FAILED";
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
esp_camera_fb_return(fb);
fb = NULL;
image = NULL;
quirc_destroy(q);
}
}
/* Function to display the results of reading the QR Code on the serial monitor. */
void dumpData(const struct quirc_data *data)
{
Serial.printf("Version: %d\n", data->version);
Serial.printf("ECC level: %c\n", "MLHQ"[data->ecc_level]);
Serial.printf("Mask: %d\n", data->mask);
Serial.printf("Length: %d\n", data->payload_len);
Serial.printf("Payload: %s\n", data->payload);
QRCodeResult = (const char *)data->payload;
}
|
__________________________________________________________
3.- Servidor web cliente de un Router. Se observa el QR en una página web.
- Se crea un servidor web y una página web.
- La ESP32-CAM lee un código QR, este se observa en una página web que podemos visualizar en un navegador.
- Podemos poner la luz de flash.
- Una vez decodificado el QR lo podemos copiar.
- Este código también tiene la posibilidad de encender/apagar los dos LED anteriores.
- Es necesario estar en una red WiFi y conocer el nombre de la red y su contraseña, esos datos los debemos poner en el código.
|
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "quirc.h"
#include <WiFi.h>
#include "esp_http_server.h"
#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
// LEDs GPIO
#define LED_OnBoard 4
#define LED_Green 12
#define LED_Blue 13
// creating a task handle
TaskHandle_t QRCodeReader_Task;
/* Variables declaration */
struct QRCodeData
{
bool valid;
int dataType;
uint8_t payload[1024];
int payloadLen;
};
struct quirc *q = NULL;
uint8_t *image = NULL;
struct quirc_code code;
struct quirc_data data;
quirc_decode_error_t err;
struct QRCodeData qrCodeData;
String QRCodeResult = "";
String QRCodeResultSend = "";
bool ws_run = false;
int wsLive_val = 0;
int last_wsLive_val;
byte get_wsLive_interval = 0;
bool get_wsLive_val = true;
/* Variables for millis() */
unsigned long previousMillis = 0;
const long interval = 1000;
/* Replace with your network credentials */
const char* ssid = "NOMBRE_DE_TU_RED_WIFI";
const char* password = "CLAVE_WIFI";
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
/* Empty handle to esp_http_server */
httpd_handle_t index_httpd = NULL;
httpd_handle_t stream_httpd = NULL;
/* HTML code for index / main page */
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<html>
<head>
<title>ESP32-CAM QR Code Reader Stream Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial; text-align: center; margin:0px auto; padding-top: 10px;}
/* ----------------------------------- Slider */
.slidecontainer {
width: 100%;
}
.slider {
-webkit-appearance: none;
width: 50%;
height: 10px;
border-radius: 5px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
}
.slider:hover {
opacity: 1;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #04AA6D;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: #04AA6D;
cursor: pointer;
}
/* ----------------------------------- */
/* Stream Viewer */
img {
width: auto ;
max-width: 100% ;
height: auto ;
}
/* ----------------------------------- */
</style>
</head>
<body>
<h3>ESP32-CAM QR Code Reader Stream Web Server</h3>
<img src="" id="vdstream"><br><br>
<div class="slidecontainer">
<span style="font-size:15;">LED Flash </span>
<input type="range" min="0" max="20" value="0" class="slider" id="mySlider">
</div>
<br>
<p>QR Code Scan Result :</p>
<div style="padding: 5px; border: 3px solid #075264; text-align: center; width: 70%; margin: auto; color:#0A758F;" id="showqrcodeval"></div>
<br>
<button type="button" onclick="CopyQRCodeRslt()">Copy Result</button>
<button type="button" onclick="send_btn_cmd('clr')">Clear Result</button>
<script>
/* ----------------------------------- Calls the video stream link and displays it */
window.onload = document.getElementById("vdstream").src = window.location.href.slice(0, -1) + ":81/stream";
/* ----------------------------------- */
var slider = document.getElementById("mySlider");
/* ----------------------------------- Variable declaration and timer to display QR Code reading results. */
var myTmr;
let qrcodeval = "...";
start_timer();
/* ----------------------------------- */
/* Update the current slider value (each time you drag the slider handle) */
slider.oninput = function() {
let slider_pwm_val = "S," + slider.value;
send_cmd(slider_pwm_val);
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function for sending commands */
function send_cmd(cmds) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/action?go=" + cmds, true);
xhr.send();
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Start and stop the timer */
function start_timer() {
myTmr = setInterval(myTimer, 500)
}
function stop_timer() {
clearInterval(myTmr)
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Timer to get QR Code reading result and display it. */
function myTimer() {
getQRCodeVal();
textQRCodeVal();
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to display the results of reading the QR Code. */
function textQRCodeVal() {
document.getElementById("showqrcodeval").innerHTML = qrcodeval;
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to send commands to the ESP32 Cam whenever the button is clicked. */
function send_btn_cmd(cmds) {
let btn_cmd = "B," + cmds;
send_cmd(btn_cmd);
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to copy QR Code reading result to clipboard. */
// Source: https://techoverflow.net/2018/03/30/copying-strings-to-the-clipboard-using-pure-javascript/
function CopyQRCodeRslt() {
// Create new element
var el = document.createElement('textarea');
// Set value (string to be copied)
el.value = qrcodeval;
// Set non-editable to avoid focus and move outside of view
el.setAttribute('readonly', '');
el.style = {position: 'absolute', left: '-9999px'};
document.body.appendChild(el);
// Select text inside element
el.select();
// Copy text to clipboard
document.execCommand('copy');
// Remove temporary element
document.body.removeChild(el);
/* Alert the copied text */
alert("The result of reading the QR Code has been copied.");
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to get QR Code reading results. */
function getQRCodeVal() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
qrcodeval = this.responseText;
}
};
xhttp.open("GET", "/getqrcodeval", true);
xhttp.send();
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
</script>
</body>
</html>
)rawliteral";
/* Index handler function to be called during GET or uri request */
static esp_err_t index_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, (const char *)INDEX_HTML, strlen(INDEX_HTML));
}
/* ________________________________________________________________________________ */
/* Stream handler function to be called during GET or uri request. */
static esp_err_t stream_handler(httpd_req_t *req){
ws_run = true;
vTaskDelete(QRCodeReader_Task);
Serial.print("stream_handler running on core ");
Serial.println(xPortGetCoreID());
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
/* Loop to show streaming video from ESP32 Cam camera and read QR Code. */
while(true){
ws_run = true;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed (stream_handler)");
res = ESP_FAIL;
} else {
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
QRCodeResult = "Decoding FAILED";
Serial.println(QRCodeResult);
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
image = NULL;
quirc_destroy(q);
if(fb->width > 200){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
}
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
wsLive_val++;
if (wsLive_val > 999) wsLive_val = 0;
}
/* ---------------------------------------- */
return res;
}
/* ________________________________________________________________________________ */
/* cmd handler function to be called during GET or uri request. */
static esp_err_t cmd_handler(httpd_req_t *req){
char* buf;
size_t buf_len;
char variable[32] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "go", variable, sizeof(variable)) == ESP_OK) {
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
int res = 0;
Serial.print("Incoming command : ");
Serial.println(variable);
Serial.println();
String getData = String(variable);
String resultData = getValue(getData, ',', 0);
/* Controlling the LEDs on the ESP32 Cam board with PWM. */
// Example :
// Incoming command = S,10
// S = Slider
// 10 = slider value
// I set the slider value range from 0 to 20.
// Then the slider value is changed from 0 - 20 or vice versa to 0 - 255 or vice versa.
if (resultData == "S") {
resultData = getValue(getData, ',', 1);
int pwm = map(resultData.toInt(), 0, 20, 0, 255);
ledcSetup(2, 5000, 8);
ledcAttachPin(4, 2);
ledcWrite(2,pwm);
}
/* ---------------------------------------- */
/* Clean the result of reading the QR Code. */
// Incoming Command = B,clr
// B = Button
// clr = Command to clean the results of reading the QR Code.
if (resultData == "B") {
resultData = getValue(getData, ',', 1);
if (resultData == "clr") {
QRCodeResult = "";
}
}
/* ---------------------------------------- */
if(res){
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
/* ________________________________________________________________________________ */
/* qrcoderslt handler function to be called during GET or uri request. */
static esp_err_t qrcoderslt_handler(httpd_req_t *req){
if (QRCodeResult != "Decoding FAILED") QRCodeResultSend = QRCodeResult;
httpd_resp_send(req, QRCodeResultSend.c_str(), HTTPD_RESP_USE_STRLEN);
return ESP_OK;
}
/* ________________________________________________________________________________ */
/* Subroutine for starting the web server / startCameraServer. */
void startCameraWebServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80;
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL
};
httpd_uri_t cmd_uri = {
.uri = "/action",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL
};
httpd_uri_t qrcoderslt_uri = {
.uri = "/getqrcodeval",
.method = HTTP_GET,
.handler = qrcoderslt_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
if (httpd_start(&index_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(index_httpd, &index_uri);
httpd_register_uri_handler(index_httpd, &cmd_uri);
httpd_register_uri_handler(index_httpd, &qrcoderslt_uri);
}
config.server_port += 1;
config.ctrl_port += 1;
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
Serial.println();
Serial.println("Camera Server started successfully");
Serial.print("Camera Stream Ready! Go to: http://");
Serial.println(WiFi.localIP());
Serial.println();
}
/* ___________________ */
/* VOID SETUP() */
void setup() {
// put your setup code here, to run once:
// Disable brownout detector.
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
/* Init serial communication speed (baud rate). */
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
/* ---------------------------------------- */
pinMode(LED_OnBoard, OUTPUT);
pinMode(LED_Green, OUTPUT);
pinMode(LED_Blue, OUTPUT);
/* Camera configuration. */
Serial.println("Start configuring and initializing the camera...");
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 = 10000000;
config.pixel_format = PIXFORMAT_GRAYSCALE;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 15;
config.fb_count = 1;
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA);
Serial.println("Configure and initialize the camera successfully.");
Serial.println();
/* ---------------------------------------- */
/* ---------------------------------------- Connect to Wi-Fi. */
WiFi.mode(WIFI_STA);
Serial.println("------------");
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
/* ::::::::::::::::: The process of connecting ESP32 CAM with WiFi Hotspot / WiFi Router. */
/*
* The process timeout of connecting ESP32 CAM with WiFi Hotspot / WiFi Router is 20 seconds.
* If within 20 seconds the ESP32 CAM has not been successfully connected to WiFi, the ESP32 CAM will restart.
* I made this condition because on my ESP32-CAM, there are times when it seems like it can't connect to WiFi,
* so it needs to be restarted to be able to connect to WiFi.
*/
int connecting_process_timed_out = 20; //--> 20 = 20 seconds.
connecting_process_timed_out = connecting_process_timed_out * 2;
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
digitalWrite(LED_OnBoard, HIGH);
delay(250);
digitalWrite(LED_OnBoard, LOW);
delay(250);
if(connecting_process_timed_out > 0) connecting_process_timed_out--;
if(connecting_process_timed_out == 0) {
delay(1000);
ESP.restart();
}
}
digitalWrite(LED_OnBoard, LOW);
Serial.println("");
Serial.println("WiFi connected");
Serial.println("------------");
Serial.println("");
/* ::::::::::::::::: */
/* ---------------------------------------- */
// Start camera web server
startCameraWebServer();
// Calls the createTaskQRCodeReader() subroutine.
createTaskQRCodeReader();
}
/* ________________________________________________________________________________ */
void loop() {
// put your main code here, to run repeatedly:
/* ---------------------------------------- Condition to check whether the index page is being accessed or not. */
// If the index page is not accessed, the loop will call the "QRCodeReader()" Subroutine.
// If the index page is accessed, the Loop will not call the "QRCodeReader()" Subroutine.
// I created this condition because the camera cannot be accessed at the same time by the index page
// and the "QRCodeReader()" subroutine.
// Meanwhile, I designed this project to be able to read the QR Code when the index page is accessed or
// the index page is not being accessed.
// Even if I have to share camera data, I haven't found the best way to share camera data
// to the "QRCodeReader()" sub routine and stream function.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (ws_run == true) {
if (get_wsLive_val == true) {
last_wsLive_val = wsLive_val;
get_wsLive_val = false;
}
get_wsLive_interval++;
if (get_wsLive_interval > 2) {
get_wsLive_interval = 0;
get_wsLive_val = true;
if (wsLive_val == last_wsLive_val) {
ws_run = false;
last_wsLive_val = 0;
createTaskQRCodeReader();
}
}
}
}
/* ---------------------------------------- */
}
/* ________________________________________________________________________________ */
/* create "QRCodeReader_Task" using the xTaskCreatePinnedToCore() function */
void createTaskQRCodeReader() {
xTaskCreatePinnedToCore(
QRCodeReader, /* Task function. */
"QRCodeReader_Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&QRCodeReader_Task, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
}
/* ________________________________________________________________________________ */
/* QRCodeReader() */
void QRCodeReader( void * pvParameters ){
Serial.print("QRCodeReader running on core ");
Serial.println(xPortGetCoreID());
while(!ws_run){
camera_fb_t * fb = NULL;
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
fb = esp_camera_fb_get();
if (!fb)
{
Serial.println("Camera capture failed (QRCodeReader())");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
//Serial.println(count);
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
QRCodeResult = "Decoding FAILED";
Serial.println(QRCodeResult);
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
esp_camera_fb_return(fb);
fb = NULL;
image = NULL;
quirc_destroy(q);
}
}
/* ________________________________________________________________________________ */
/* Function to display the results of reading the QR Code on the serial monitor. */
void dumpData(const struct quirc_data *data)
{
Serial.printf("-Version: %d\n", data->version);
Serial.printf("-ECC level: %c\n", "MLHQ"[data->ecc_level]);
Serial.printf("-Mask: %d\n", data->mask);
Serial.printf("-Length: %d\n", data->payload_len);
Serial.printf("-Payload: %s\n", data->payload);
QRCodeResult = (const char *)data->payload;
cmd_execution();
}
/* ________________________________________________________________________________ */
/* Subroutine to execute commands based on the results of reading the QR Code. */
void cmd_execution() {
if (QRCodeResult == "LED BLUE ON") digitalWrite(LED_Blue, HIGH);
if (QRCodeResult == "LED BLUE OFF") digitalWrite(LED_Blue, LOW);
if (QRCodeResult == "LED GREEN ON") digitalWrite(LED_Green, HIGH);
if (QRCodeResult == "LED GREEN OFF") digitalWrite(LED_Green, LOW);
}
/* ________________________________________________________________________________ */
/* String function to process the data command */
// I got this from : https://www.electroniclinic.com/reyax-lora-based-multiple-sensors-monitoring-using-arduino/
String getValue(String data, char separator, int index) {
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
|
__________________________________________________________
4.- Servidor web Punto de Acceso. Se observa el QR en una página web.
- Este código es similar al anterior, pero ahora el ESP32-CAM no está conectado a un Router, el crea su propia red.
- Debemos entrar en la configuración de nuestro WiFi y cambiar a la red que establece el ESP32-CAM, en este caso se denomina: ESP32-CAMQR.
- Una vez que hemos entrado en su red, escribimos en un navegador su IP: 192.168.1.1.
- Observa en el código estas líneas en donde está el nombre de la red y la clave para entrar:
const char* ssid = "ESP32-CAMQR"; //--> access point name
const char* password = "123456"; //--> access point password
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
LectorQRWebPuntoAcceso.ino
|
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "quirc.h"
#include <WiFi.h>
#include "esp_http_server.h"
#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
// LEDs GPIO
#define LED_OnBoard 4
#define LED_Green 12
#define LED_Blue 13
// creating a task handle
TaskHandle_t QRCodeReader_Task;
/* Variables declaration */
struct QRCodeData
{
bool valid;
int dataType;
uint8_t payload[1024];
int payloadLen;
};
struct quirc *q = NULL;
uint8_t *image = NULL;
struct quirc_code code;
struct quirc_data data;
quirc_decode_error_t err;
struct QRCodeData qrCodeData;
String QRCodeResult = "";
String QRCodeResultSend = "";
bool ws_run = false;
int wsLive_val = 0;
int last_wsLive_val;
byte get_wsLive_interval = 0;
bool get_wsLive_val = true;
/* Variables for millis() */
unsigned long previousMillis = 0;
const long interval = 1000;
/* Punto de Acceso */
const char* ssid = "ESP32-CAMQR"; //--> access point name
const char* password = "123456"; //--> access point password
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
/* Empty handle to esp_http_server */
httpd_handle_t index_httpd = NULL;
httpd_handle_t stream_httpd = NULL;
/* HTML code for index / main page */
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<html>
<head>
<title>ESP32-CAM QR Code Reader Stream Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial; text-align: center; margin:0px auto; padding-top: 10px;}
/* ----------------------------------- Slider */
.slidecontainer {
width: 100%;
}
.slider {
-webkit-appearance: none;
width: 50%;
height: 10px;
border-radius: 5px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
}
.slider:hover {
opacity: 1;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #04AA6D;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: #04AA6D;
cursor: pointer;
}
/* ----------------------------------- */
/* Stream Viewer */
img {
width: auto ;
max-width: 100% ;
height: auto ;
}
/* ----------------------------------- */
</style>
</head>
<body>
<h3>ESP32-CAM QR Code Reader Stream Web Server</h3>
<img src="" id="vdstream"><br><br>
<div class="slidecontainer">
<span style="font-size:15;">LED Flash </span>
<input type="range" min="0" max="20" value="0" class="slider" id="mySlider">
</div>
<br>
<p>QR Code Scan Result :</p>
<div style="padding: 5px; border: 3px solid #075264; text-align: center; width: 70%; margin: auto; color:#0A758F;" id="showqrcodeval"></div>
<br>
<button type="button" onclick="CopyQRCodeRslt()">Copy Result</button>
<button type="button" onclick="send_btn_cmd('clr')">Clear Result</button>
<script>
/* ----------------------------------- Calls the video stream link and displays it */
window.onload = document.getElementById("vdstream").src = window.location.href.slice(0, -1) + ":81/stream";
/* ----------------------------------- */
var slider = document.getElementById("mySlider");
/* ----------------------------------- Variable declaration and timer to display QR Code reading results. */
var myTmr;
let qrcodeval = "...";
start_timer();
/* ----------------------------------- */
/* Update the current slider value (each time you drag the slider handle) */
slider.oninput = function() {
let slider_pwm_val = "S," + slider.value;
send_cmd(slider_pwm_val);
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function for sending commands */
function send_cmd(cmds) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/action?go=" + cmds, true);
xhr.send();
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Start and stop the timer */
function start_timer() {
myTmr = setInterval(myTimer, 500)
}
function stop_timer() {
clearInterval(myTmr)
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Timer to get QR Code reading result and display it. */
function myTimer() {
getQRCodeVal();
textQRCodeVal();
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to display the results of reading the QR Code. */
function textQRCodeVal() {
document.getElementById("showqrcodeval").innerHTML = qrcodeval;
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to send commands to the ESP32 Cam whenever the button is clicked. */
function send_btn_cmd(cmds) {
let btn_cmd = "B," + cmds;
send_cmd(btn_cmd);
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to copy QR Code reading result to clipboard. */
// Source: https://techoverflow.net/2018/03/30/copying-strings-to-the-clipboard-using-pure-javascript/
function CopyQRCodeRslt() {
// Create new element
var el = document.createElement('textarea');
// Set value (string to be copied)
el.value = qrcodeval;
// Set non-editable to avoid focus and move outside of view
el.setAttribute('readonly', '');
el.style = {position: 'absolute', left: '-9999px'};
document.body.appendChild(el);
// Select text inside element
el.select();
// Copy text to clipboard
document.execCommand('copy');
// Remove temporary element
document.body.removeChild(el);
/* Alert the copied text */
alert("The result of reading the QR Code has been copied.");
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
/* Function to get QR Code reading results. */
function getQRCodeVal() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
qrcodeval = this.responseText;
}
};
xhttp.open("GET", "/getqrcodeval", true);
xhttp.send();
}
/* :::::::::::::::::::::::::::::::::::::::::::::::: */
</script>
</body>
</html>
)rawliteral";
/* Index handler function to be called during GET or uri request */
static esp_err_t index_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, (const char *)INDEX_HTML, strlen(INDEX_HTML));
}
/* ________________________________________________________________________________ */
/* Stream handler function to be called during GET or uri request. */
static esp_err_t stream_handler(httpd_req_t *req){
ws_run = true;
vTaskDelete(QRCodeReader_Task);
Serial.print("stream_handler running on core ");
Serial.println(xPortGetCoreID());
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
/* Loop to show streaming video from ESP32 Cam camera and read QR Code. */
while(true){
ws_run = true;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed (stream_handler)");
res = ESP_FAIL;
} else {
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
QRCodeResult = "Decoding FAILED";
Serial.println(QRCodeResult);
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
image = NULL;
quirc_destroy(q);
if(fb->width > 200){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
}
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
wsLive_val++;
if (wsLive_val > 999) wsLive_val = 0;
}
/* ---------------------------------------- */
return res;
}
/* ________________________________________________________________________________ */
/* cmd handler function to be called during GET or uri request. */
static esp_err_t cmd_handler(httpd_req_t *req){
char* buf;
size_t buf_len;
char variable[32] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "go", variable, sizeof(variable)) == ESP_OK) {
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
int res = 0;
Serial.print("Incoming command : ");
Serial.println(variable);
Serial.println();
String getData = String(variable);
String resultData = getValue(getData, ',', 0);
/* Controlling the LEDs on the ESP32 Cam board with PWM. */
// Example :
// Incoming command = S,10
// S = Slider
// 10 = slider value
// I set the slider value range from 0 to 20.
// Then the slider value is changed from 0 - 20 or vice versa to 0 - 255 or vice versa.
if (resultData == "S") {
resultData = getValue(getData, ',', 1);
int pwm = map(resultData.toInt(), 0, 20, 0, 255);
ledcSetup(2, 5000, 8);
ledcAttachPin(4, 2);
ledcWrite(2,pwm);
}
/* ---------------------------------------- */
/* Clean the result of reading the QR Code. */
// Incoming Command = B,clr
// B = Button
// clr = Command to clean the results of reading the QR Code.
if (resultData == "B") {
resultData = getValue(getData, ',', 1);
if (resultData == "clr") {
QRCodeResult = "";
}
}
/* ---------------------------------------- */
if(res){
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
/* ________________________________________________________________________________ */
/* qrcoderslt handler function to be called during GET or uri request. */
static esp_err_t qrcoderslt_handler(httpd_req_t *req){
if (QRCodeResult != "Decoding FAILED") QRCodeResultSend = QRCodeResult;
httpd_resp_send(req, QRCodeResultSend.c_str(), HTTPD_RESP_USE_STRLEN);
return ESP_OK;
}
/* ________________________________________________________________________________ */
/* Subroutine for starting the web server / startCameraServer. */
void startCameraWebServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80;
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL
};
httpd_uri_t cmd_uri = {
.uri = "/action",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL
};
httpd_uri_t qrcoderslt_uri = {
.uri = "/getqrcodeval",
.method = HTTP_GET,
.handler = qrcoderslt_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
if (httpd_start(&index_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(index_httpd, &index_uri);
httpd_register_uri_handler(index_httpd, &cmd_uri);
httpd_register_uri_handler(index_httpd, &qrcoderslt_uri);
}
config.server_port += 1;
config.ctrl_port += 1;
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
Serial.println();
Serial.println("Camera Server started successfully");
Serial.print("Camera Stream Ready! Go to: http://");
Serial.println(local_ip);
Serial.println();
}
/* ___________________ */
/* VOID SETUP() */
void setup() {
// put your setup code here, to run once:
// Disable brownout detector.
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
/* Init serial communication speed (baud rate). */
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
/* ---------------------------------------- */
pinMode(LED_OnBoard, OUTPUT);
pinMode(LED_Green, OUTPUT);
pinMode(LED_Blue, OUTPUT);
/* Camera configuration. */
Serial.println("Start configuring and initializing the camera...");
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 = 10000000;
config.pixel_format = PIXFORMAT_GRAYSCALE;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 15;
config.fb_count = 1;
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA);
Serial.println("Configure and initialize the camera successfully.");
Serial.println();
/* ---------------------------------------- */
/* ---------------------------------------- Wi-Fi connection */
WiFi.softAP(ssid, password); //--> Creating Access Points
WiFi.softAPConfig(local_ip, gateway, subnet);
// Start camera web server
startCameraWebServer();
// Calls the createTaskQRCodeReader() subroutine.
createTaskQRCodeReader();
}
/* ________________________________________________________________________________ */
void loop() {
// put your main code here, to run repeatedly:
/* ---------------------------------------- Condition to check whether the index page is being accessed or not. */
// If the index page is not accessed, the loop will call the "QRCodeReader()" Subroutine.
// If the index page is accessed, the Loop will not call the "QRCodeReader()" Subroutine.
// I created this condition because the camera cannot be accessed at the same time by the index page and the "QRCodeReader()" subroutine.
// Meanwhile, I designed this project to be able to read the QR Code when the index page is accessed or the index page is not being accessed.
// Even if I have to share camera data, I haven't found the best way to share camera data to the "QRCodeReader()" sub routine and stream function.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (ws_run == true) {
if (get_wsLive_val == true) {
last_wsLive_val = wsLive_val;
get_wsLive_val = false;
}
get_wsLive_interval++;
if (get_wsLive_interval > 2) {
get_wsLive_interval = 0;
get_wsLive_val = true;
if (wsLive_val == last_wsLive_val) {
ws_run = false;
last_wsLive_val = 0;
createTaskQRCodeReader();
}
}
}
}
/* ---------------------------------------- */
}
/* ________________________________________________________________________________ */
/* create "QRCodeReader_Task" using the xTaskCreatePinnedToCore() function */
void createTaskQRCodeReader() {
xTaskCreatePinnedToCore(
QRCodeReader, /* Task function. */
"QRCodeReader_Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&QRCodeReader_Task, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
}
/* ________________________________________________________________________________ */
/* QRCodeReader() */
void QRCodeReader( void * pvParameters ){
Serial.print("QRCodeReader running on core ");
Serial.println(xPortGetCoreID());
while(!ws_run){
camera_fb_t * fb = NULL;
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
fb = esp_camera_fb_get();
if (!fb)
{
Serial.println("Camera capture failed (QRCodeReader())");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
//Serial.println(count);
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
QRCodeResult = "Decoding FAILED";
Serial.println(QRCodeResult);
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
esp_camera_fb_return(fb);
fb = NULL;
image = NULL;
quirc_destroy(q);
}
}
/* ________________________________________________________________________________ */
/* Function to display the results of reading the QR Code on the serial monitor. */
void dumpData(const struct quirc_data *data)
{
Serial.printf("-Version: %d\n", data->version);
Serial.printf("-ECC level: %c\n", "MLHQ"[data->ecc_level]);
Serial.printf("-Mask: %d\n", data->mask);
Serial.printf("-Length: %d\n", data->payload_len);
Serial.printf("-Payload: %s\n", data->payload);
QRCodeResult = (const char *)data->payload;
cmd_execution();
}
/* ________________________________________________________________________________ */
/* Subroutine to execute commands based on the results of reading the QR Code. */
void cmd_execution() {
if (QRCodeResult == "LED BLUE ON") digitalWrite(LED_Blue, HIGH);
if (QRCodeResult == "LED BLUE OFF") digitalWrite(LED_Blue, LOW);
if (QRCodeResult == "LED GREEN ON") digitalWrite(LED_Green, HIGH);
if (QRCodeResult == "LED GREEN OFF") digitalWrite(LED_Green, LOW);
}
/* ________________________________________________________________________________ */
/* String function to process the data command */
// I got this from : https://www.electroniclinic.com/reyax-lora-based-multiple-sensors-monitoring-using-arduino/
String getValue(String data, char separator, int index) {
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
|
__________________________________________________________
5.- Lee QR y enciende/apaga dos LEDs. Además envía la información por Bluetooth a una app realizada con App Inventor.
p62D_esp32_bluetooth_QR_5.aia
- Este ejemplo es parecido al que vimos en el punto 2, en este caso además de encender/apagar dos LED se envía la información por Bluetooth a una aplicación realizada con App Inventor.
- Librería BluetoothSerial: 150_Wemos_BluetoothClasico.htm
_________________
- Diseño.
_________________
- Bloques.
ESP32-SdCard-Bluetooth.in |
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "quirc.h"
// creating a task handle
TaskHandle_t QRCodeReader_Task;
/* GPIO of CAMERA_MODEL_AI_THINKER */
#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
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth no activado! Activa la conexion Bluetooth.
#endif
BluetoothSerial SerialBT;
/* Variables declaration */
struct QRCodeData
{
bool valid;
int dataType;
uint8_t payload[1024];
int payloadLen;
};
struct quirc *q = NULL;
uint8_t *image = NULL;
camera_fb_t * fb = NULL;
struct quirc_code code;
struct quirc_data data;
quirc_decode_error_t err;
struct QRCodeData qrCodeData;
String QRCodeResult = "";
/* VOID SETTUP() */
void setup() {
// Disable brownout detector.
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
/* Init serial communication speed (baud rate). */
Serial.begin(115200);
SerialBT.begin("ESP32test");
Serial.setDebugOutput(true);
Serial.println();
/* Camera configuration. */
Serial.println("Start configuring and initializing the camera...");
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 = 10000000;
config.pixel_format = PIXFORMAT_GRAYSCALE;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 15;
config.fb_count = 1;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA);
Serial.println("Configure and initialize the camera successfully.");
Serial.println();
/* Create "QRCodeReader_Task" using the xTaskCreatePinnedToCore() function */
xTaskCreatePinnedToCore(
QRCodeReader, /* Task function. */
"QRCodeReader_Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&QRCodeReader_Task, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
}
void loop() {
// put your main code here, to run repeatedly:
delay(1);
}
/* The function to be executed by "QRCodeReader_Task" */
// This function is to instruct the camera to take or capture a QR Code image,
// then it is processed and translated into text.
void QRCodeReader( void * pvParameters ){
Serial.println("QRCodeReader is ready.");
Serial.print("QRCodeReader running on core ");
Serial.println(xPortGetCoreID());
Serial.println();
/* Loop to read QR Code in real time. */
while(1){
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
fb = esp_camera_fb_get();
if (!fb)
{
Serial.println("Camera capture failed");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
Serial.println("Decoding FAILED");
QRCodeResult = "Decoding FAILED";
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
esp_camera_fb_return(fb);
fb = NULL;
image = NULL;
quirc_destroy(q);
}
}
/* Function to display the results of reading the QR Code on the serial monitor. */
void dumpData(const struct quirc_data *data)
{
Serial.printf("Version: %d\n", data->version);
Serial.printf("ECC level: %c\n", "MLHQ"[data->ecc_level]);
Serial.printf("Mask: %d\n", data->mask);
Serial.printf("Length: %d\n", data->payload_len);
Serial.printf("Payload: %s\n", data->payload);
QRCodeResult = (const char *)data->payload;
SerialBT.println(QRCodeResult);
}
|
__________________________________________________________
6.- Guarda su información en una tarjeta SdCard externa.
- Ejemplo sencillo para grabar información en la SdCard de la ESP32, probado con ESP32-CAM.
- La SdCard que he utilizado es la de color negro de la izquierda de 32 GB, en cambio con la tarjeta de la derecha no me funcionó.
- Observa que utiliza la librería SD_MMC
ESP32-SdCard.in |
#include "SD_MMC.h"
// Archivo para escribir los datos
File dataFile;
void setup() {
Serial.begin(115200);
// Inicializar el módulo de tarjeta SD
if (!SD_MMC.begin()) {
Serial.println("Error al inicializar el módulo de tarjeta SD");
return;
}
Serial.println("Módulo de tarjeta SD correcto.");
// Crear o abrir el archivo para escritura
dataFile = SD_MMC.open("/datos.txt", FILE_WRITE);
if (!dataFile) {
Serial.println("Error al abrir el archivo");
return;
}
Serial.println("Archivo abierto correctamente");
}
void loop() {
// Obtener datos para guardar
String datos = "Datos a guardar";
// Escribir los datos en el archivo
dataFile.println(datos);
dataFile.flush();
Serial.println("Datos guardados correctamente");
delay(1000);
}
|
__________________________________________________________
7.- Leer QR y guardar su información en una tarjeta SdCard externa.
LectorQRWebPuntoAcceso.ino
|
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "quirc.h"
// creating a task handle
TaskHandle_t QRCodeReader_Task;
/* GPIO of CAMERA_MODEL_AI_THINKER */
#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
#include "SD_MMC.h"
// Archivo para escribir los datos
File dataFile;
/* Variables declaration */
struct QRCodeData
{
bool valid;
int dataType;
uint8_t payload[1024];
int payloadLen;
};
struct quirc *q = NULL;
uint8_t *image = NULL;
camera_fb_t * fb = NULL;
struct quirc_code code;
struct quirc_data data;
quirc_decode_error_t err;
struct QRCodeData qrCodeData;
String QRCodeResult = "";
/* VOID SETTUP() */
void setup() {
// Disable brownout detector.
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
/* Init serial communication speed (baud rate). */
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
// Inicializar el módulo de tarjeta SD
if (!SD_MMC.begin()) {
Serial.println("Error al inicializar el módulo de tarjeta SD");
return;
}
Serial.println("Módulo de tarjeta SD correcto.");
// Crear o abrir el archivo para escritura
dataFile = SD_MMC.open("/datos.txt", FILE_WRITE);
if (!dataFile) {
Serial.println("Error al abrir el archivo");
return;
}
Serial.println("Archivo abierto correctamente");
///// Fin tarjeta SdCard.
/* Camera configuration. */
Serial.println("Start configuring and initializing the camera...");
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 = 10000000;
config.pixel_format = PIXFORMAT_GRAYSCALE;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 15;
config.fb_count = 1;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA);
Serial.println("Configure and initialize the camera successfully.");
Serial.println();
/* Create "QRCodeReader_Task" using the xTaskCreatePinnedToCore() function */
xTaskCreatePinnedToCore(
QRCodeReader, /* Task function. */
"QRCodeReader_Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&QRCodeReader_Task, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
}
void loop() {
// put your main code here, to run repeatedly:
delay(1);
}
/* The function to be executed by "QRCodeReader_Task" */
// This function is to instruct the camera to take or capture a QR Code image,
// then it is processed and translated into text.
void QRCodeReader( void * pvParameters ){
Serial.println("QRCodeReader is ready.");
Serial.print("QRCodeReader running on core ");
Serial.println(xPortGetCoreID());
Serial.println();
/* Loop to read QR Code in real time. */
while(1){
q = quirc_new();
if (q == NULL){
Serial.print("can't create quirc object\r\n");
continue;
}
fb = esp_camera_fb_get();
if (!fb)
{
Serial.println("Camera capture failed");
continue;
}
quirc_resize(q, fb->width, fb->height);
image = quirc_begin(q, NULL, NULL);
memcpy(image, fb->buf, fb->len);
quirc_end(q);
int count = quirc_count(q);
if (count > 0) {
quirc_extract(q, 0, &code);
err = quirc_decode(&code, &data);
if (err){
Serial.println("Decoding FAILED");
QRCodeResult = "Decoding FAILED";
} else {
Serial.printf("Decoding successful:\n");
dumpData(&data);
}
Serial.println();
}
esp_camera_fb_return(fb);
fb = NULL;
image = NULL;
quirc_destroy(q);
}
}
/* Function to display the results of reading the QR Code on the serial monitor. */
void dumpData(const struct quirc_data *data)
{
Serial.printf("Version: %d\n", data->version);
Serial.printf("ECC level: %c\n", "MLHQ"[data->ecc_level]);
Serial.printf("Mask: %d\n", data->mask);
Serial.printf("Length: %d\n", data->payload_len);
Serial.printf("Payload: %s\n", data->payload);
QRCodeResult = (const char *)data->payload;
dataFile.println(QRCodeResult);
dataFile.flush();
}
|
_______________________________
|