Neste tutorial você verá como é possível tirar fotos com ESP32-CAM e armazenar essas imagens no Google Drive.

Hoje existem diversas câmeras espalhadas pelo mundo, tornando-o mais seguro por um lado e menos privado por outro. Com o avanço da tecnologia e a chegada das placas de desenvolvimento, cada vez mais podemos criar nosso próprios protótipos e desenvolver aplicações que nos trarão benefícios para nosso cotidiano.
Mas que benefício eu posso conseguir através das câmeras? Como posso criar algum projeto com câmera que traga algum beneficio ao meu cotidiano? Pois bem, através deste tutorial você conhecerá o ESP32 CAM e como é possível através dele tirar fotos para armazenar no Google Drive e verá onde você pode aplicar este tutorial a um projeto.
Se interessou? Então continue lendo!
Material necessário
Para fazer o projeto você precisará dos seguintes componentes:
01 – Módulo ESP32-CAM com Câmera OV2640 2MP
01 – Módulo Conversor USB TTL CP2102 Serial RS232
01 – Jumpers Fêmea-Fêmea x 40 unidades
01 – Fonte DC Chaveada 5V 3A Micro USB
01 – Cabo micro USB 1 metro
Serviço Web necessário
Para fazer o carregamento das fotos utilizaremos o Google Drive.
O Google Drive é um serviço de armazenamento e sincronização de arquivos grátis até 15 GB, que oferece a edição de documentos, de apresentações, upload e download de imagens, entre outras coisas.
Funcionamento do Circuito
O circuito é composto pelo ESP32 CAM juntamente com o Conversor USB TTL. O conversor USB será utilizado apenas para fazer a gravação no ESP32 CAM. Após carregar o código para a placa é possível utilizar uma fonte externa para alimentação do ESP respeitando a tensão contínua de 5V.
Depois de carregado o código no módulo, o ESP32 CAM se conectará a uma rede WiFi e fará a captura de uma imagem e à enviará a sua conta do Google Drive repetindo esse processo de captura e envio em aproximadamente 8 a 10 segundos.

Montagem do circuito
Com todos os componentes em mãos vamos à montagem do circuito. Abaixo temos o esquemático eletrônico montado em uma protoboard.

Obs.: o pino IO0 deve ser conectado ao GND apenas para carregar o código no ESP32 CAM.
Configuração do Google Drive
Após montado o circuito, vamos a configuração do Google Drive para receber as fotos que serão enviadas através do ESP32-CAM.
Primeiramente, você deve criar uma conta Google para utilizar o Google Drive, caso não tenha uma conta crie uma utilizando este link. Depois de criada a conta acesse a raiz do Google Drive como mostra a imagem abaixo adicionando o código.
No Google Drive clique com o botão direito em Meu Drive > Mais > Script do Google Apps.
No Script iremos adicionar o código para o Google Drive salvar a imagem quando recebê-la. Então apague este código function myFunction( ) e adicione o código abaixo.
function doPost(e) { var imagem = Utilities.base64Decode(e.parameters.data);//Decofica a imagem var nome_do_Arquivo = Utilities.formatDate(new Date(), "GMT-3", "dd/MM/yyyy-HH:mm:ss")+".jpg"; //Define nome da imagem com a data e o horário var salvar_imagem = Utilities.newBlob(imagem, e.parameters.mimetype, nome_do_Arquivo); var pasta, pastas = DriveApp.getFoldersByName("ESP32-CAM"); //Verifica se a pasta já existe if (pastas.hasNext()) { pasta = pastas.next(); } else { pasta = DriveApp.createFolder("ESP32-CAM"); //Cria a pasta } var Arquivar = pasta.createFile(salvar_imagem); //Salva o arquivo na pasta return ContentService.createTextOutput('Completo') }
Após adicionar o código no Script clique em Publicar > Implantar como aplicativo da web… e dê um nome para o projeto e clique em OK.
Depois de clicar em OK você deve selecionar a opção Anyone, even anonymous e depois clicar em Deploy.
Após clicar em Deploy aparecerá uma tela perguntando sobre a permissão em acessar sua conta, clique em Analisar permissões e depois selecione sua conta do Google.
Depois de selecionar a conta clique em Avançado e depois Acessar upload (não seguro).
Após clicar em Acessar upload clique em Permitir.
Após permitir clique em Deploy novamente aparecerá um link para fazer a comunicação com o código no Script.
Você deverá salvar este link em um bloco de notas para posteriormente usarmos ele no código que será carregado na ESP32-CAM.
Depois se salvar o link e clicar em OK você pode fechar a aba do projeto e está finalizada a parte de configuração do Google Drive. Logo você vai poder tirar fotos com ESP32-CAM!
Bibliotecas e gerenciador de placas
Após configurado o Google Drive vamos a adição de bibliotecas necessárias para o funcionamento do código e instalação da placa no IDE do Arduino. Assim, após essa última configuração, você poderá finalmente tirar fotos com ESP32-CAM.
Será necessário utilizar a biblioteca Base64.
Para usar esta biblioteca coloque os arquivos Base64.cpp e Base64.h na pasta onde tem seu código de programação para o ESP32-CAM como mostra a imagem abaixo.

Posteriormente mostraremos qual código será colocado dentro do arquivo .ino que aparece na imagem acima.
Obs.: Caso você já tenha instalado o ESP 32 na IDE do Arduino, pule esta etapa.
Na Arduino IDE vá em Arquivos > Preferências e adicione o link abaixo em “URLs Adicionais para Gerenciadores de Placas” e clique em OK.
https://dl.espressif.com/dl/package_esp32_index.json
Depois vá em Ferramentas > Placas > Gerenciador de Placas… e pesquise ESP32 e clique em instalar.

Após instalado a placa vá em Ferramentas > Placa e selecione a placa AI Thinker ESP32-CAM.

Código
Com o circuito montado e o Google Drive configurado vamos ao código que será carregado no ESP32 CAM.
Adicione no código nas variáveis ssid e password os dados de conexão da sua rede wi-fi.
//Dados para conexão com a rede Wi-fi const char* ssid = "nome_da_rede"; //Insira o SSID da rede const char* password = "senha_da_rede"; //Insira a senha da rede
Adicione no código na variável meuScript o endereço obtido na configuração do Google Drive.
//Inserir endereço gerado pelo Google Drive String meuScript = "/macros/s/XXXXXXXXXXXXXXXXXXXXXXXXXX/exec";
Obs.: somente adicione a parte do meio do código, troque o XXXXXXXXXXXXXXXXXXXXX pelos os caracteres que adquirimos no Google Drive. Não deve ser substituído pelo link todo.
//Bibliotecas utilizadas #include <WiFi.h> #include <WiFiClientSecure.h> #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "Base64.h" #include "esp_camera.h" //Dados para conexão com a rede Wi-fi const char* ssid = "nome_da_rede"; //Insira o SSID da rede const char* password = "senha_da_rede"; //Insira a senha da rede //Dados para conexão com o Google Drive const char* host = "script.google.com"; //Inserir endereço gerado pelo Google Drive String meuScript = "/macros/s/XXXXXXXXXXXXXXXXXXXXXXXX/exec"; //Dados para o arquivo de imagem String nomedoArquivo = "filename=ESP32-CAM.jpg"; String mimeType = "&mimetype=image/jpeg"; String Imagem = "&data="; int tempo_espera = 10000; //Espera 10 segundos para o Google responder //Definição dos pinos #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 flash 4 void setup() { WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); Serial.begin(115200); delay(100); WiFi.mode(WIFI_STA); Serial.println(""); Serial.print("Conectando na rede: "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } //Definindo flash da câmera pinMode(flash,OUTPUT); Serial.println("Conectado!"); Serial.println(); Serial.print("endereço STAIP: "); Serial.println(WiFi.localIP()); Serial.println(); //Configuração do pinos da câmera 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; config.frame_size = FRAMESIZE_VGA; config.jpeg_quality = 4; config.fb_count = 1; esp_err_t err = esp_camera_init(&config); //Inicialização da câmera if (err != ESP_OK) { Serial.printf("O início da câmera falhou com erro 0x%x", err);//Informa erro se a câmera não for iniciada corretamente delay(1000); ESP.restart();//Reinicia o ESP } } void loop() { Captura_Imagem(); //Captura e envia imagem delay(1000); } void Captura_Imagem() { Serial.println("Conectando ao " + String(host)); WiFiClientSecure client; if (client.connect(host, 443)) { //Conectando no Google Serial.println("Conexão com sucesso!"); camera_fb_t * fb = NULL; digitalWrite(flash,HIGH); delay(100); fb = esp_camera_fb_get(); //Função que captura imagem na ESP digitalWrite(flash,LOW); delay(100); if(!fb) { Serial.println("Falha ao capturar imagem!"); delay(1000); ESP.restart(); return; } char *input = (char *)fb->buf; char output[base64_enc_len(3)]; String imageFile = ""; for (int i=0;i<fb->len;i++) { base64_encode(output, (input++), 3); if (i%3==0) imageFile += urlencode(String(output)); } String Data = nomedoArquivo+mimeType+Imagem; esp_camera_fb_return(fb); Serial.println("Enviando imagem capturada ao Google Drive."); client.println("POST " + meuScript + " HTTP/1.1"); client.println("Host: " + String(host)); client.println("Content-Length: " + String(Data.length()+imageFile.length())); client.println("Content-Type: application/x-www-form-urlencoded"); client.println(); client.print(Data); int Index; for (Index = 0; Index < imageFile.length(); Index = Index+1000) { client.print(imageFile.substring(Index, Index+1000)); } Serial.println("Aguardando resposta."); long int tempo_inicio = millis(); while (!client.available()) { //Aguarda resposta do envio da imagem Serial.print("."); delay(100); if ((tempo_inicio+tempo_espera) < millis()) { Serial.println(); Serial.println("Sem Resposta."); break; } } Serial.println(); while (client.available()) { Serial.print(char(client.read())); //Mostra na tela a resposta } } else { Serial.println("Conexão ao " + String(host) + " falhada."); } client.stop(); } String urlencode(String str) //Função de codificação { String encodedString=""; char c; char code0; char code1; char code2; for (int i =0; i < str.length(); i++){ c=str.charAt(i); if (c == ' '){ encodedString+= '+'; } else if (isalnum(c)){ encodedString+=c; } else{ code1=(c & 0xf)+'0'; if ((c & 0xf) >9){ code1=(c & 0xf) - 10 + 'A'; } c=(c>>4)&0xf; code0=c+'0'; if (c > 9){ code0=c - 10 + 'A'; } code2='\0'; encodedString+='%'; encodedString+=code0; encodedString+=code1; } yield(); } return encodedString; }
Após adicionar o código no seu sketch que está na pasta junto com a Base64.cpp e Base64.h salve e feche seu sketch e abra-o novamente. Assim que abrir seu projeto novamente aparecerão a Base64.cpp e Base64.h da seguinte forma como mostra a imagem abaixo.

Carregando o código no ESP32 – CAM
Para carregar o código no ESP32-CAM certifique-se que o pino IO0 está conectado ao GND. Então conecte o cabo do conversor no computador e selecione a porta COM que aparecerá na IDE do arduino em Ferramentas > Porta.
Após isso faça o upload do código e quando aparecer “Connecting…” aperte o botão RST que se encontra embaixo do ESP32-CAM.

Se aparecer esta imagem significa que o código foi carregado com sucesso.

Depois de carregado o código desconecte o pino IO0 do GND e aperte o botão RST novamente, isso fará com que seu código comece a rodar no ESP32-CAM.
Depois de alguns segundos você verá no seu Google Drive as imagens chegando.

Conclusão
Bom no inicio do tutorial comentamos que onde seria possível aplicar este tutorial a um projeto. Uma ótima aplicação seria construir um Olho Mágico Smart, imagine que alguém chegue na sua casa e aperte a campainha e o ESP32-CAM dispare uma foto e envie uma notificação no seu smartphone ou até mesmo no seu smartwatch juntamente com o arquivo de imagem.
Seria um benefício ótimo não é? Utilize seus conhecimentos e tente criar este projeto e compartilhe conosco. Veja o vídeo de demonstração abaixo:
Obs: A notificação em relação ao smartwatch pode variar de acordo com a compatibilidade do mesmo. Você deve verificar como funciona o sistema de notificação do seu dispositivo e se há suporte.
Gostou de aprender como tirar fotos com o ESP32-CAM? Deixe seu comentário logo abaixo. Para saber mais sobre o mundo maker, arduino entre outros dispositivos acesse o blog.
No app do script do google da essa mensagem
Registro de execução
06:51:21 Notificação Execução iniciada
06:51:22 Erro
TypeError: Cannot read properties of undefined (reading ‘parameters’)
doPost @ Código.gs:3
Olá Gabriel
Favor entrar em contato conosco no [email protected].
Att.
Vitor Mattos.
MakerHero.
Boa noite, o apps script do google atualizou, fiquei perdido por causa disso, tem como me ajudar?
Olá Gabriel
Favor entrar em contato conosco no [email protected].
Att.
Vitor Mattos.
MakerHero.
O que causa a falha “HTTP/1.1 401 Unauthorized”?
Olá,
A falha 401 é um erro de autorização. Verifique se a URL no código está certa e se o acesso foi liberado até para anônimos como no post.
Abraços!
Vinícius – Equipe MakerHero
Olá, boa tarde!
Estou com um probleminha em relação ao Google, quando eu dou o publish e faço todo o passo a passo, ele me gera um link, porém ao usar ele link ele me retorna erro 404 ou página não encontrada.
Poderiam me dar um help, por favor?
Felipe, eu fiz tudo certinho, como muito bem explicado por vc, mas na
hora de Compilar aparece uma mensagem no IDE:
‘base64_enc_len’ e
‘Base64_encode’ was not declared in this scope
Tem como me ajudarem?
Preciso muito de tirar fotos continuas e datadas.
Agradeço!
Obs.: minha IDE a versao é 1.8.16
Olá,
Confira se você instalou a versão 1.0.4 do ESP32 conforme a figura 6.
Abraços!
Vinícius – Equipe MakerHero
Bom dia!
Alguém conseguiu resolver esse erro?
TypeError: Cannot read property ‘parameters’ of undefined
Grato
Aparentemente não tive erros com o Script do Google Drive, vejam esse outro tutorial, pode ter mais detalhes:
https://www.gsampallo.com/2019/10/13/esp32-cam-subir-fotos-a-google-drive/
Estou tendo um erro do codigo do scrypt do google na linha 3.
TypeError: Cannot read property ‘parameters’ of undefined
Olá, estou com esse mesmo problema, você conseguiu resolver?
Olá!
Testei aqui e funcionou normalmente, vocês retiraram a parte “function myFunction( )” que está por padrão no script do google?
Abraços!
Vinícius – Equipe MakerHero
Contato, gostaria de trocar uma ideia para um projeto.
Bom dia Keytson! o que seria?
Existe alguma maneira de testar o script do google? Não estou conseguindo fazer o upload da foto.
Bom dia Flavio! Pelo que eu sei, só desta maneira. Mas deve existir alguma maneira de testar pelo postman, porém não cheguei a pesquisar.
Parabéns! Muito claro e didático.
Olá Carlos,
Obrigado pela leitura!
Abraço.
Olá Felipe
Estou entrando neste mundo dos IOTs e navegando cheguei no seu post, fantástico!!! Vou tentar replicar este exemplo que postou. Super obrigado.
Olá Grenne, obrigado pela leitura! espero que consiga replicar.
Abraço!
Olá Felipe, muito obrigado pelo artigo muito bem escrito por sinal.
Implementei o projeto e ele funciona OK por um tempo e de repente começa a apresentar problemas de conexão com o Script com o erro “Conexão ao script.google.com falhada.”
Cabe mencionar que a conexão com a Internet funciona OK.
Vc poderia, por favor, me dar alguma luz sobre o que pode estar acontecendo e como resolver?
Muito obrigado desde já.
Olá Simon, obrigado pela leitura!
Em quanto tempo ocorreu esse erro após implementado?
Felipe, obrigado pela pronta resposta.
Aconteu pela primeira vez uns 5 minutos após a implementação. Agora continua acontecendo de tempos em tempos (não consigo identificar um padrão) e também começou a aparecer um novo problema: a conexão com o Script acontece OK porem a transferencia da imagem não completa. Já aumentei o tempo de espera de resposta do Google para 20 seg porem continuo recebendo a mensagem “Sem Resposta”. Pode ter alguma coisa a ver com os limites do Google?
Então Simon, sem dúvida é a relação com os limites do google. Dê uma olhada nas limitações através desse link.
https://developers.google.com/apps-script/guides/services/quotas
Aumente o tempo do delay(1000) para delay(30000) creio que isso resolverá o problema de conexão do script, com relação a transferência de imagem não completa é necessário olhar os parâmetros de qualidade se estiver muito alta, a transferência não ocorre por completo.
Pelos testes que realizei esses parâmetros de qualidade foram os melhores que encontrei para o envio da foto.
Se o problema persistir altere
config.frame_size = FRAMESIZE_VGA;
para
config.frame_size = FRAMESIZE_CIF;
Isso deve ajudar na transferência porém a imagem ficará com menos resolução.
Felipe, enquanto aguardava sua resposta e para verificar se o problema poderia ser com os limites do Google criei uma conta nova, e logo de cara o problema de não conseguir transferir a imagem aconteceu novamente, então a minha conclusão é que não é por isso.
Por outro lado a minha imagem já esta com baixa resolução, o tamanho do arquivo é de <50K…
Acho que tem alguma outra coisa que esta pegando. Já tentei também com outra conexão de Wifi (alias eu tenho 200M de upload) e com uma fonte de alimentação de maior potencia e também não adiantou…
Existe alguma outra alternativa que eu possa utilizar, por exemplo fazer um FTP ou enviar para Dropbox? Procurei na internet e não achei nada até agora
Você aumentou o tempo de envio da foto para 30 segundos e continuou o problema?
Felipe, estou respondendo aqui sua ultima pergunta porque por algum motivo o link para “Responder” não aparece no Browser…
Vc diz:
“Você aumentou o tempo de envio da foto para 30 segundos e continuou o problema?”
E a resposta é sim, (entendendo que quando vc fala de tempo de envio estamos falando do tempo de espera) eu mudei para:
int tempo_espera = 30000; //Espera 30 segundos para o Google responder
Existe algum ftp client para a ESP32 Cam? Eu poderia usar um servidor de ftp talvez seja mais tranquilo…
Então Simon esse é o tempo de espera para o google retornar uma resposta se a imagem foi enviada ou não.
Você tem que mudar o tempo que demora para capturar e enviar a foto
o código está assim:
Captura_Imagem(); //Captura e envia imagem
delay(1000);
mude para:
Captura_Imagem(); //Captura e envia imagem
delay(30000);
Sobre o FTP eu não sei te responder pois não pesquisei nada sobre esse assunto, e de acordo com o código a imagem é enviada em base64 e quando chega no servidor é decodificada de volta.
Caro Felipe, muito obrigado pelas sua atenção e disponibilidade para ajudar. Me desculpe por estar tomando tanto seu tempo mas acho que eventualmente outros usuarios podem vir a encontrar o mesmo problema (já vi ele reportado em alguns sites internacionais e também sem solução:
https://www.gsampallo.com/2019/10/13/esp32-cam-subir-fotos-a-google-drive/?unapproved=345&moderation-hash=096b9a92ccad34761de666172a40e7b6#comment-345
Post do Guillermo Leon de de 3 de Marzo de 2020.
Bom voltando ao tema acontece que eu estou tentando enviar uma única foto logo no reset (ultima instrução do Setup) e assim o meu loop esta vazio…
P.S: achei um ftp (https://github.com/blackcodetavern/ESP32_FTPClient) estou fazendo os primeiros testes e até agora funciona OK.
Felipe, muito obrigado pela sua atenção e pela disposição para ajudar.
Eu estou tentando enviar uma única imagem. Em outras palavras meu Loop esta vazio. Eu inseri Captura_Imagem(); //Captura e envia imagem como ultima instrução do Setup…
Olá Pessoal, alguem consegiu fazer funcionar por bastante tempo? Alguma dica? Eu não consigo que funcione consistentemente conforme descrito acima.
Simon,
Não se é uma solução viável, mas eu pensei em uma divisão de tarefas. O ESP32-Cam bate a foto e envia ela para o local mais próximo, e ele teria o script para se conectar, enviar ou tentar novamente.
Este local, poderia ser uma máquina na rede, ali ter um python, bat, shell que continuaria….
Estou com mesmo problema. conseguiu resolver?
Bom dia.
Gostei muito da ideia …
A única coisa ruim para mim seria a pouca qualidade da imagem, um módulos pequeno como este porém com mais qualidade seria OV5640 que possui 5Mp.
Poderia trabalhar de igual maneira !? Enviar fotos para o Google Drive!?
É possível efetuar a mesma configuração no módulo da câmera OV5640, para capturar fotos de melhor qualidade comparado ao utilizado neste seu projeto!?
Este módulo possui foco automático, qual seria a programação para está !?
Obrigado
Boa tarde Pedro!
Bom pelos testes que eu realizei, não é possível aumentar a qualidade. Eu tentei enviar imagens com maior qualidade alterando as configurações da câmera pois essas imagens que foram enviadas não estão na qualidade máxima. Quando eu tento mandar com maior qualidade a imagem chega cortada no google drive.
E pelas especificações o foco dela é fixo.
OI! Comprei recentemente uma espcam e resolvi testar o código, porém está aparecendo esse erro:
[E][camera.c:1049] camera_probe(): Detected camera not supported.
[E][camera.c:1249] esp_camera_init(): Camera probe failed with error 0x20004
Pelo que entendi, conectou certinho na rede, mas a camera não captura a imagem. Será que veio com defeito?
Boa tarde Erika obrigado pela leitura, creio que deve ser má conexão do cabo flat, pois tive esse problema também…sugiro a você que tire o cabo flat da câmera e conecte novamente com cuidado para não danificar o equipamento, isso deve resolver o problema.
Erika,
Tente um outro cabo, pode estar tendo algum problema de alimentação.
Abraços!
Diogo – Equipe MakerHero