Hoje, podemos afirmar que a inteligência artificial faz parte do nosso dia a dia, tanto em tarefas pessoais quanto profissionais, oferecendo suporte em atividades repetitivas ou na resolução de dúvidas teóricas. Neste artigo, vamos mostrar como integrar um projeto de eletrônica com inteligência artificial, demonstrando mais uma aplicação prática da IA em nosso ambiente profissional.
Para colocar esse conceito em prática, iremos desenvolver um projeto onde coletaremos dados reais do ambiente por meio de um sensor conectado ao ESP32. Esses sensores geram uma grande quantidade de dados por segundo, e se fôssemos analisar cada dado individualmente, o processo seria muito demorado. Para resolver isso, integraremos o sistema com uma inteligência artificial através da API do Gemini, que será responsável por analisar os dados e gerar um relatório com as principais informações que desejamos. Para visualizar esse relatório, será necessário acessar uma página web onde o retorno da API será exibido.
Para realizarmos este projeto, é importante entender alguns conceitos antes de partir para a prática. Portanto, recomendamos ter conhecimento prévio sobre o ESP32 e o conceito de API.
No contexto atual, existem diversas formas de interagir com inteligência artificial. Por exemplo, várias empresas oferecem uma versão gratuita de chats que permitem a comunicação com IA, como o ChatGPT, Copilot, Gemini, entre outros. No entanto, esses chats são compostos por páginas web que facilitam o acesso. Contudo, para integrar IA em nossos projetos, esse tipo de acesso não é tão útil. Por isso, podemos utilizar as mesmas funções presentes nos chats sem a interface, através de APIs. Cada empresa possui seus próprios requisitos para utilizar suas APIs, mas iremos utilizar a da Google o Gemini, que possui requisitos simples e uma documentação bem estruturada.
Primeiramente, para acessar a API da Gemini e utilizá-la, é necessário seguir alguns passos simples.
Passo 1: Acesse a página oficial da Gemini e crie uma conta ou faça login no site.
Passo 2: Após realizar o login e acessar a página que permite a geração de uma chave de API, a qual será de grande importância ao longo do projeto, devemos acessar o seguinte link
Passo 3: Agora que estamos na página, devemos gerar uma chave de API a partir do menu lateral esquerdo, na opção “Get API Key”. Após selecionar essa opção, será aberta, no espaço ao lado, uma breve explicação sobre a chave de API e, logo em seguida, um botão “Criar chave API”, onde devemos clicar para gerar a chave.
Passo 4: Após clicar no botão, para gerar a chave de API, o processo é simples. Devemos selecionar um projeto na Google Cloud. Por padrão, existe o projeto ‘Generative Language Client’, que podemos utilizar. Dessa forma, selecionamos o projeto existente e, após isso, clicamos no botão ‘Criar uma chave de API em um projeto atual.
Passo 5: Assim que os passos anteriores forem finalizados, podemos ver em uma área os dados gerados, como a chave de API e, também, algo muito importante: o plano que está incluso na utilização da chave que acabou de ser criada. Portanto, para a utilização em nosso projeto, deve ser aparecer a opção sem custo financeiro.
Passo 6: Para finalizar, após conferir as informações sobre sua chave de API, devemos copiá-la e armazená-la em um local seguro de sua escolha, visto que a utilizaremos em nosso projeto para realizar a integração do ESP32 com a inteligência artificial. IMPORTANTE: salve essa chave em um local seguro, pois é um dado sensível e será de grande importância no desenvolvimento do projeto.
Como a maioria das APIs públicas possui documentação e padrões de utilização, o Gemini não é diferente. Portanto, apresentaremos algumas características fundamentais da documentação da API para que possamos utilizá-la corretamente em nosso projeto. Para isso, será preciso seguir alguns passos simples, nos quais iremos acessar a documentação e visualizar duas informações muito importantes.
Primeiro: Para acessar a documentação, é bem simples. Basta acessar este link, onde temos a documentação oficial.
Segundo: Após isso, devemos analisar o menu lateral esquerdo, onde estão os principais tópicos presentes na documentação. Para o momento, abordaremos o tópico API Keys, onde são tratados os assuntos de authentication e making-requests para a construção do nosso projeto.
Authentication: O conteúdo deste tópico explica como deve ser realizada a autenticação ao utilizar a API. Portanto, não podemos apenas utilizá-la diretamente; devemos entender que, para obter os resultados esperados da API, é necessário seguir o padrão informado na documentação. Para isso, é preciso gerar a chave de API e, ao fazer a requisição, passar no cabeçalho da solicitação o campo x-goog-api-key: ${API_KEY}
com a chave gerada.
Making-requests: Para trabalhar com a API, será necessário entender o que eles esperam receber e o que devemos esperar como respostas. Este tópico introduz como devemos enviar nossas solicitações, o que queremos e como receber e tratar as informações entregues pela API.
Agora que entendemos e configuramos a API da gemini, podemos realizar um teste simples para compreender melhor sua utilização e as possibilidades de integração com projetos IoT. Para a execução do nosso projeto, e até mesmo do teste, será necessário instalar uma IDE onde iremos escrever o código, como o Arduino IDE, o VSCode com PlatformIO, ou outra de sua preferência.
IMPORTANTE: Para realizar qualquer requisição à API da gemini, devemos utilizar a chave de API que foi gerada anteriormente, portanto, é necessário deixá-la pronta para ser utilizada.
Para o exemplo básico de integração da API da gemini com o ESP32, iremos criar uma página web simples para facilitar a visualização e interação. Ela servirá apenas para enviar perguntas e exibir as respostas. O processo pode ser dividido em duas partes:
Detalhamento do código:
#include <WiFi.h> #include <WebServer.h> #include <HTTPClient.h> #include <WiFiClientSecure.h> #include <ArduinoJson.h>
Primeiramente, devemos importar as bibliotecas que iremos utilizar. Nesse caso, utilizaremos apenas as bibliotecas básicas do ESP32 e a biblioteca ArduinoJson para tratar o retorno da API. Portanto, a biblioteca ArduinoJson deve ser instalada.
const char* ssid = "SEU_SSID"; const char* password = "SUA_SENHA";
Em seguida, criamos duas variáveis onde iremos armazenar as informações sobre o Wi-Fi ao qual o ESP32 será conectado. É muito importante colocar corretamente o nome (SSID) e a senha da rede Wi-Fi escolhida, visto que sem essas informações a conexão não funcionará.
const String apiKey = "SUA_CHAVE_API_GEMINI"; const String endpoint = "https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent";
Assim como criamos duas variáveis para armazenar os dados do Wi-Fi, também iremos criar mais duas variáveis onde colocaremos a chave de API que geramos anteriormente neste artigo, além da URL base das requisições para a API da gemini.
WebServer server(80);
Definimos a porta na qual o servidor web será iniciado.
String createPage(String response = "") { String html = "<!DOCTYPE html><html lang='pt'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>"; html += "<title>Pergunte à OpenAI</title></head><body>"; html += "<h1>Pergunte à OpenAI</h1>"; html += "<form action='/ask' method='POST'><label for='question'>Digite sua pergunta:</label>"; html += "<input type='text' id='question' name='question'><br><br>"; html += "<input type='submit' value='Enviar'></form>"; if (response != "") { html += "<h2>Resposta:</h2><p>" + response + "</p>"; } html += "</body></html>"; return html; }
Criamos a função responsável por retornar uma string que contém nosso código HTML, o qual construirá nossa interface quando for chamado.
String askGemini(String question) { WiFiClientSecure client; HTTPClient http; client.setInsecure(); // Desabilita verificação de certificado SSL para testes http.begin(client, endpoint); http.addHeader("Content-Type", "application/json"); http.addHeader("x-goog-api-key", apiKey); // Cabeçalho de autenticação correto para a API Gemini // Corpo da requisição JSON para a API Gemini String jsonRequest = "{\"contents\": [{\"role\": \"user\", \"parts\": [{\"text\": \"" + question + "\"}]}]}"; Serial.println("Enviando requisição para a API Gemini..."); int httpResponseCode = http.POST(jsonRequest); String payload = http.getString(); Serial.print("Código de resposta HTTP: "); Serial.println(httpResponseCode); if (httpResponseCode > 0) { Serial.print("Resposta da API: "); Serial.println(payload); } else { Serial.print("Erro na requisição: "); Serial.println(http.errorToString(httpResponseCode).c_str()); } http.end(); if (httpResponseCode == 200) { // Usando ArduinoJson para extrair a resposta StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, payload); if (!error) { // Acessa o valor de "text" const char* response = doc["candidates"][0]["content"]["parts"][0]["text"]; return response; // Retorna o valor } else { return "Erro ao analisar JSON."; } } else { return "Erro ao se comunicar com a API Gemini"; } }
No trecho acima, temos a função responsável por realizar a requisição à API. Em outras palavras, essa função recebe uma string como parâmetro e a utiliza no corpo da solicitação para a API da gemini.
void handleRoot() { server.send(200, "text/html", createPage()); }
O objetivo dessa função é apenas carregar o HTML ao acessar a URL com o tipo de conteúdo text/html.
void handleAsk() { if (server.method() == HTTP_POST) { if (server.hasArg("question")) { String question = server.arg("question"); String response = askGemini(question); server.send(200, "text/html", createPage(response)); } else { server.send(400, "text/plain", "Pergunta não fornecida"); } } else { server.send(405, "text/plain", "Método não permitido. Utilize POST."); } }
A função handleAsk realiza uma validação para verificar se existe alguma pergunta. Caso exista, a função askGemini(question) será chamada com a pergunta como parâmetro, enviando a requisição. Caso não exista, uma mensagem será exibida na interface informando que nenhuma pergunta foi fornecida.
void setup() { Serial.begin(9600); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Conectando ao WiFi..."); } Serial.println("Conectado!"); // Exibe o IP do ESP32 após a conexão com o Wi-Fi Serial.print("Endereço IP do ESP32: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/ask", HTTP_ANY, handleAsk); server.begin(); Serial.println("Servidor iniciado"); }
A função void setup
realiza a inicialização do script, onde configuramos a porta serial para comunicação com a velocidade de 115200 baud. Em seguida, o ESP32 tenta se conectar ao Wi-Fi usando as credenciais fornecidas nas variáveis ssid
e password
. O código entra em um laço while
que verifica o status da conexão, imprimindo a mensagem “Conectando ao WiFi…” a cada segundo até que a conexão seja estabelecida. Uma vez conectado, a mensagem “Conectado!” é exibida no monitor serial.
Depois disso, a configuração do servidor web é realizada. A rota padrão " / "
é associada à função handleRoot
, que será chamada sempre que alguém acessar a página inicial. Esta função normalmente contém o HTML da interface que será exibida no navegador.
Além disso, a rota "/ask"
é configurada para responder a requisições HTTP POST, utilizando a função handleAsk
. Esta função trata o envio de perguntas à API do gemini ou qualquer outra lógica associada.
Finalmente, o servidor web é iniciado com o comando server.begin()
, e a mensagem “Servidor iniciado” é exibida no monitor serial, indicando que o servidor está pronto para aceitar conexões.
void loop() { server.handleClient(); }
A função void loop
é o coração do código que executa repetidamente enquanto o ESP32 estiver ligado. No caso deste exemplo, ela contém uma única linha de código: server.handleClient();
. Esta função monitora continuamente o servidor web em busca de novas requisições de clientes.
Sempre que um cliente (como um navegador ou dispositivo externo) faz uma requisição HTTP ao ESP32, o método handleClient()
processa essa requisição. Ele verifica as rotas definidas previamente no setup
(como " / "
e "/ask"
) e executa as funções associadas a essas rotas, como handleRoot
e handleAsk
, conforme a URL e o método HTTP da requisição (GET, POST, etc.).
Esse processo é executado repetidamente no loop, garantindo que o servidor esteja sempre pronto para lidar com requisições de clientes a qualquer momento, sem a necessidade de parar ou reiniciar o ESP32.
#include <WiFi.h> #include <WebServer.h> #include <HTTPClient.h> #include <WiFiClientSecure.h> #include <ArduinoJson.h> // Inclua a biblioteca ArduinoJson // Configurações WiFi const char* ssid = "SEU_SSID"; const char* password = "SUA_SENHA"; // Configuração da API do Gemini const String apiKey = "chave da API Gemini"; // Substitua pela chave da API Gemini const String endpoint = "https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent"; // Endpoint para a API Gemini // Servidor Web WebServer server(80); // Função para criar a página HTML String createPage(String response = "") { String html = "<!DOCTYPE html><html lang='pt'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>"; html += "<title>Pergunte à Gemini</title></head><body>"; html += "<h1>Pergunte à Gemini</h1>"; html += "<form action='/ask' method='POST'><label for='question'>Digite sua pergunta:</label>"; html += "<input type='text' id='question' name='question'><br><br>"; html += "<input type='submit' value='Enviar'></form>"; if (response != "") { html += "<h2>Resposta:</h2><p>" + response + "</p>"; } html += "</body></html>"; return html; } // Função para enviar a pergunta para a API Gemini String askGemini(String question) { WiFiClientSecure client; HTTPClient http; client.setInsecure(); // Desabilita verificação de certificado SSL para testes http.begin(client, endpoint); http.addHeader("Content-Type", "application/json"); http.addHeader("x-goog-api-key", apiKey); // Cabeçalho de autenticação correto para a API Gemini // Corpo da requisição JSON para a API Gemini String jsonRequest = "{\"contents\": [{\"role\": \"user\", \"parts\": [{\"text\": \"" + question + "\"}]}]}"; Serial.println("Enviando requisição para a API Gemini..."); int httpResponseCode = http.POST(jsonRequest); String payload = http.getString(); Serial.print("Código de resposta HTTP: "); Serial.println(httpResponseCode); if (httpResponseCode > 0) { Serial.print("Resposta da API: "); Serial.println(payload); } else { Serial.print("Erro na requisição: "); Serial.println(http.errorToString(httpResponseCode).c_str()); } http.end(); if (httpResponseCode == 200) { // Usando ArduinoJson para extrair a resposta StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, payload); if (!error) { // Acessa o valor de "text" const char* response = doc["candidates"][0]["content"]["parts"][0]["text"]; return response; // Retorna o valor } else { return "Erro ao analisar JSON."; } } else { return "Erro ao se comunicar com a API Gemini"; } } // Rota para a página inicial void handleRoot() { server.send(200, "text/html", createPage()); } // Rota para processar a pergunta void handleAsk() { if (server.method() == HTTP_POST) { if (server.hasArg("question")) { String question = server.arg("question"); String response = askGemini(question); server.send(200, "text/html", createPage(response)); } else { server.send(400, "text/plain", "Pergunta não fornecida"); } } else { server.send(405, "text/plain", "Método não permitido. Utilize POST."); } } void setup() { Serial.begin(9600); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Conectando ao WiFi..."); } Serial.println("Conectado!"); // Exibe o IP do ESP32 após a conexão com o Wi-Fi Serial.print("Endereço IP do ESP32: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/ask", HTTP_ANY, handleAsk); server.begin(); Serial.println("Servidor iniciado"); } void loop() { server.handleClient(); }
Agora que vimos e entendemos a utilização básica da API do Gemini, vamos aplicá-la em um projeto com um uso mais prático, onde, através de sensores, podemos coletar medições reais do ambiente. Com esses dados, teremos informações suficientes para solicitar à IA que gere uma análise e nos retorne um relatório com pontos relevantes.
Para a construção deste projeto, vamos desenvolver um script responsável por coletar os dados, realizar a conexão com a internet, gerar a página web onde mostraremos o relatório gerado pela IA, e, por fim, a parte onde enviaremos os dados juntamente com a informação que queremos para a IA. Para isso, utilizaremos as seguintes bibliotecas:
Antes de analisarmos e lermos os comentários do código por completo, vamos examinar a função principal que realiza a requisição à API do Gemini.
String enviarDadosParaGemini() { WiFiClientSecure client; // Cria um cliente seguro para HTTPS HTTPClient http; // Cria uma instância HTTP para a requisição client.setTimeout(120000); // Define o timeout para 2 minutos client.setInsecure(); // Desabilita a verificação SSL http.begin(client, endpoint); // Inicia a requisição HTTP com o endpoint da API http.addHeader("Content-Type", "application/json"); // Define o cabeçalho do tipo de conteúdo http.addHeader("x-goog-api-key", apiKey); // Define o cabeçalho da chave da API // Cria o corpo da requisição com os dados coletados String jsonRequest = "{\"contents\": [{\"role\": \"user\", \"parts\": [{\"text\": \"Baseado nos seguintes dados de temperatura e umidade do ambiente: ["; for (auto& data : dadosColetados) { // Adiciona cada par de dados de temperatura e umidade ao JSON jsonRequest += "{umidade:" + data.umidade + ",temperatura:" + data.temperatura + "},"; } jsonRequest.remove(jsonRequest.length() - 1); // Remove a última vírgula do JSON jsonRequest +="],Me retorne uma análise do ambiente com as seguintes informações no formato de texto corrido: Alerta de extremidade de temperatura (muito alta ou muito baixa), alerta de extremidade de umidade (muito alta ou muito baixa), umidade média (calculada de acordo com os dados fornecidos), temperatura média (calculada de acordo com os dados fornecidos), recomendação de temperatura e umidade mais adequadas, e dicas para um ambiente agradável.\"}]}]}"; // Finaliza o JSON Serial.println(jsonRequest); // Exibe o corpo da requisição no Serial int httpResponseCode = http.POST(jsonRequest); // Envia a requisição POST String payload = http.getString(); // Armazena a resposta da API Serial.println(payload); // Exibe a resposta no Serial http.end(); // Encerra a requisição HTTP if (httpResponseCode == 200) { // Se a resposta for sucesso (código 200) dadosColetados.clear(); // Limpa os dados coletados após o envio // Usando ArduinoJson para extrair a resposta StaticJsonDocument<200> doc; // Cria um documento JSON estático DeserializationError error = deserializeJson(doc, payload); // Deserializa a resposta JSON if (!error) { // Se não houver erro na deserialização const char* response = doc["candidates"][0]["content"]["parts"][0]["text"]; // Extrai o texto de resposta return response; // Retorna o texto da resposta } else { return "Erro ao analisar JSON."; // Retorna erro de análise JSON } } else { return "Erro ao se comunicar com a API Gemini"; // Retorna erro de comunicação } }
No código acima, primeiramente, realizamos a inicialização de duas variáveis responsáveis por permitir a requisição à API: WiFiClientSecure
, para gerenciar conexões HTTPS, e HTTPClient
, para enviar as requisições HTTP. Em seguida, definimos um tempo de espera (timeout) de 2 minutos, já que o tempo de resposta da API pode variar bastante dependendo da qualidade da conexão com a internet. Também desabilitamos a verificação SSL com client.setInsecure()
, o que pode ser útil em testes, mas não é recomendado para ambientes de produção por motivos de segurança.
Depois, construímos a requisição à API. Primeiro, definimos os cabeçalhos necessários, como o tipo de conteúdo e a chave da API. A seguir, criamos o conteúdo da requisição (corpo), que é armazenado na variável jsonRequest
. Nesse ponto, adicionamos a mensagem inicial, e, em seguida, utilizamos um loop que itera sobre os dados coletados pelo sensor (temperatura e umidade), incorporando-os à mensagem. Após o loop, finalizamos o JSON adicionando um texto que especifica à IA o que queremos como resposta e o formato desejado.
Por fim, realizamos a verificação do retorno da API. Se o código de resposta for 200 (que significa “OK”), utilizamos a biblioteca ArduinoJson
para analisar a resposta e extrair apenas o campo do JSON que desejamos. Caso haja um erro na deserialização do JSON, retornamos uma mensagem de erro. Se o código de resposta for diferente de 200, retornamos também uma mensagem indicando erro na comunicação com a API.
O restante do código já é familiar: conectamos ao Wi-Fi, coletamos os dados usando a biblioteca do sensor DHT11, e, por último, iniciamos o servidor web com uma página HTML que exibe as informações (A url para acessar é o IP do Esp32/relatório).
#include <WiFi.h> // Inclui a biblioteca para manipulação de conexões WiFi #include <WebServer.h> // Inclui a biblioteca para criar um servidor web #include <HTTPClient.h> // Inclui a biblioteca para realizar requisições HTTP #include <WiFiClientSecure.h> // Inclui a biblioteca para usar HTTPS (SSL/TLS) #include <DHT.h> // Inclui a biblioteca para o sensor de temperatura e umidade DHT11 #include <ArduinoJson.h> // Inclui a biblioteca para manipulação de dados JSON // Definições de pinos #define DHTPIN 4 // Define o pino 4 como o pino de dados do sensor DHT11 #define DHTTYPE DHT11 // Define o tipo do sensor como DHT11 #define LED_SUCCESS 2 // Define o pino 2 para o LED de sucesso #define LED_ERROR 15 // Define o pino 15 para o LED de erro // Configurações WiFi const char *ssid = "Nome Da Rede"; // Define o SSID da rede WiFi const char *password = "Senha da Rede"; // Define a senha da rede WiFi // Configuração da API do Gemini const String apiKey = "AIzaSy..."; // Chave de API do Gemini (abreviada por questões de segurança) const String endpoint = "https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent"; // URL da API // Instâncias do sensor e servidor web DHT dht(DHTPIN, DHTTYPE); // Cria uma instância do sensor DHT11 WebServer server(80); // Cria uma instância do servidor web rodando na porta 80 // Estrutura para armazenar os dados coletados do sensor struct SensorData { String umidade; // Armazena a umidade coletada String temperatura; // Armazena a temperatura coletada }; std::vector<SensorData> dadosColetados; // Vetor para armazenar vários dados coletados // Função para formatar a string para HTML String formatarStringParaHTML(String texto) { // Substituir asteriscos duplos (**) por tags <strong> para negrito texto.replace("**", "<strong>"); // Alternar entre abertura e fechamento da tag <strong> bool abrirTag = true; while (texto.indexOf("<strong>") != -1) { if (abrirTag) { texto.replace("<strong>", "<strong>"); } else { texto.replace("<strong>", "</strong>"); } abrirTag = !abrirTag; } // Substituir '\n' por '<br>' para quebras de linha texto.replace("\n", "<br>"); return texto; // Retorna a string formatada } // Função para coletar dados do sensor DHT11 void coletarDados() { float h = dht.readHumidity(); // Lê a umidade do sensor float t = dht.readTemperature(); // Lê a temperatura do sensor if (isnan(h) || isnan(t)) { // Verifica se houve erro na leitura digitalWrite(LED_ERROR, HIGH); // Acende o LED de erro Serial.println("Erro ao ler o sensor DHT11"); return; // Sai da função se houver erro } else { digitalWrite(LED_SUCCESS, HIGH); // Acende o LED de sucesso SensorData data; // Cria uma nova estrutura de dados data.umidade = String(h, 2); // Armazena a umidade com 2 casas decimais data.temperatura = String(t, 2); // Armazena a temperatura com 2 casas decimais dadosColetados.push_back(data); // Adiciona os dados coletados ao vetor } digitalWrite(LED_ERROR, LOW); // Apaga o LED de erro } // Função para enviar dados à API do Gemini String enviarDadosParaGemini() { WiFiClientSecure client; // Cria um cliente seguro para HTTPS HTTPClient http; // Cria uma instância HTTP para a requisição client.setTimeout(120000); // Define o timeout para 2 minutos client.setInsecure(); // Desabilita a verificação SSL (para testes) http.begin(client, endpoint); // Inicia a requisição HTTP com o endpoint da API http.addHeader("Content-Type", "application/json"); // Define o cabeçalho do tipo de conteúdo http.addHeader("x-goog-api-key", apiKey); // Define o cabeçalho da chave da API // Cria o corpo da requisição com os dados coletados String jsonRequest = "{\"contents\": [{\"role\": \"user\", \"parts\": [{\"text\": \"Baseado nos seguintes dados de temperatura e umidade do ambiente: ["; for (auto& data : dadosColetados) { // Adiciona cada par de dados de temperatura e umidade ao JSON jsonRequest += "{umidade:" + data.umidade + ",temperatura:" + data.temperatura + "},"; } jsonRequest.remove(jsonRequest.length() - 1); // Remove a última vírgula do JSON jsonRequest += "], Me retorne uma análise do ambiente com as seguintes informações no formato de texto corrido: Alerta de extremidade de temperatura (muito alta ou muito baixa), alerta de extremidade de umidade (muito alta ou muito baixa), umidade média (calculada de acordo com os dados fornecidos), temperatura média (calculada de acordo com os dados fornecidos), recomendação de temperatura e umidade mais adequadas, e dicas para um ambiente agradável.\"}]}]}"; // Finaliza o JSON Serial.println(jsonRequest); // Exibe o corpo da requisição no Serial int httpResponseCode = http.POST(jsonRequest); // Envia a requisição POST String payload = http.getString(); // Armazena a resposta da API Serial.println(payload); // Exibe a resposta no Serial http.end(); // Encerra a requisição HTTP if (httpResponseCode == 200) { // Se a resposta for sucesso (código 200) dadosColetados.clear(); // Limpa os dados coletados após o envio // Usando ArduinoJson para extrair a resposta StaticJsonDocument<200> doc; // Cria um documento JSON estático DeserializationError error = deserializeJson(doc, payload); // Deserializa a resposta JSON if (!error) { // Se não houver erro na deserialização const char* response = doc["candidates"][0]["content"]["parts"][0]["text"]; // Extrai o texto de resposta return response; // Retorna o texto da resposta } else { return "Erro ao analisar JSON."; // Retorna erro de análise JSON digitalWrite(LED_ERROR, HIGH); // Acende o LED de erro } } else { return "Erro ao se comunicar com a API Gemini"; // Retorna erro de comunicação digitalWrite(LED_ERROR, HIGH); // Acende o LED de erro } } // Função para criar a página HTML com o relatório String gerarRelatorioWeb(String response) { String html = "<!DOCTYPE html><html lang='pt'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>"; // Cabeçalho HTML html += "<title>Relatório do Ambiente</title></head><body>"; // Título da página html += "<h1>Relatório do Ambiente</h1>"; // Cabeçalho H1 // Exibe os dados retornados pela API if (response != "") { // Se houver resposta da API html += "<p>" + formatarStringParaHTML(response) + "</p>"; // Formata e exibe a resposta } else { html += "<p>Nenhum dado coletado até o momento.</p>"; // Caso não haja resposta } html += "</body></html>"; // Finaliza o corpo HTML return html; // Retorna o HTML gerado } // Rota para exibir o relatório void handleRelatorio() { String response = enviarDadosParaGemini(); // Envia os dados para a API e recebe a resposta server.send(200, "text/html", gerarRelatorioWeb(response)); // Envia a resposta HTML ao cliente } // Função para configuração do ESP32 void setup() { Serial.begin(115200); // Inicia a comunicação serial a 115200 bps // Inicializa o sensor DHT11 dht.begin(); // Inicia o sensor DHT11 // Configura pinos dos LEDs pinMode(LED_SUCCESS, OUTPUT); // Define o pino do LED de sucesso como saída pinMode(LED_ERROR, OUTPUT); // Define o pino do LED de erro como saída // Conecta ao WiFi WiFi.begin(ssid, password); // Inicia a conexão WiFi while (WiFi.status() != WL_CONNECTED) { // Aguarda até conectar ao WiFi delay(1000); // Espera 1 segundo Serial.println("Conectando ao WiFi..."); } Serial.println("Conectado ao WiFi!"); // Exibe mensagem de sucesso na conexão // Exibe o IP do ESP32 após a conexão com o Wi-Fi Serial.print("Endereço IP do ESP32: "); Serial.println(WiFi.localIP()); // Mostra o endereço IP do ESP32 // Inicializa servidor web server.on("/relatorio", handleRelatorio); // Define a rota para acessar o relatório server.begin(); // Inicia o servidor web Serial.println("Servidor web iniciado"); // Coleta inicial de dados coletarDados(); // Coleta dados logo após a inicialização } // Função para rodar continuamente void loop() { server.handleClient(); // Mantém o servidor web ativo static unsigned long ultimoEnvio = 0; // Variável para controlar o tempo de envio static unsigned long ultimaColeta = 0; // Variável para controlar o tempo de coleta // Coletar dados a cada 30 segundos if (millis() - ultimaColeta > 30000) { // Se 30 segundos se passaram desde a última coleta coletarDados(); // Coleta dados do sensor ultimaColeta = millis(); // Atualiza o tempo da última coleta } // Enviar dados a cada 2 minutos if (millis() - ultimoEnvio > 120000) { // Se 2 minutos se passaram desde o último envio enviarDadosParaGemini(); // Envia os dados para a API ultimoEnvio = millis(); // Atualiza o tempo do último envio } }
Para finalizar nosso projeto, iremos construir a parte física. Para isso, devemos seguir as instruções abaixo.
Mais uma vez, finalizamos um projeto que oferece uma vasta gama de possibilidades para incrementos. Assim, quero desafiar vocês a implementar mais funcionalidades no projeto e até mesmo criar novas ideias utilizando inteligência artificial.
Contudo, devemos sempre lembrar que, com a evolução da tecnologia, é fundamental que também busquemos nos aprimorar constantemente, incorporando essas inovações em nosso contexto.
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!