O monitoramento de dados climáticos atua em benefícios da qualidade de vida humana, auxiliando tanto em uma simples prevenção, quanto como ferramenta fundamental em setores agrícolas. A coleta das informações necessárias para a caracterização do clima será realizada através de sensores e instrumentos, com a capacidade de avaliar a temperatura, umidade, pressão atmosférica, radiação solar, possíveis indícios de chuva, entre outras variáveis. Neste post iremos propor a construção de uma estação meteorológica com um ESP32, capaz de expressar os valores coletados pelos sensores em uma plataforma composta por gráficos e ferramentas voltadas a análise climática. O sistema será alocado em um servidor online, armazenando as informações coletadas na rede, através das ferramentas de edição Node-RED e IBM Cloud.
Componentes
Para concluir as atividades desse post, tenha em mãos os seguintes componentes:
- Placa DOIT ESP32 - ESP-WROOM-32 - WiFi / Bluetooth;
- Led Alto Brilho RGB - 5mm;
- Resistor 330R - 1/4W - 5%;
- Kit Jumper Macho Macho;
- Protoboard 400 Pontos;
- Sensor de Pressão/ Temperatura/ Umidade - BME 280;
- Sensor de Luz Ultravioleta UV ML8511;
- Sensor de Chuva;
- Conversor AC/DC 90~240 VAC - 5VDC/1A - JP4;
- Fonte 12V - 5V/3,3V p/ Protoboard;
Você pode compra-los clicando nos links acima ou visitando nosso site: www.curtocircuito.com.br.
Circuito Elétrico
A construção do circuito elétrico irá exigir um valor de correte elétrica maior do que o fornecido internamente em placas DOIT ESP32, portanto, iremos utilizar uma fonte de Protoboard como meio de fornecer uma alimentação externa para o projeto. A tensão de saída da fonte poderá ser ajustada entre 5V e 3,3V de acordo com a posição dos plugs amarelos, destacados na imagem abaixo, e no caso desse projeto, iremos ajusta-la em 3,3V. Verifique a polaridade da fonte antes de conectá-la ao Protoboard.
LEDs RGB possuem quatro terminais, sendo três responsáveis por emitir as cores e um (o maior entre eles) a polaridade. A alimentação do LED será dividida entre Ánodo ou Catodo comu, se for anodo conecte a fileira positiva, se for catodo na fileira negativa.
Encaixe o LED no Protoboard, conectando os resistores de 330 Ω entre os pinos do LED e as portas digitais D02, D04 e D23 do ESP32, e alimente o pino maior de acordo com o tipo de LED.
Sensor de Chuva
Este componente emite leituras analógicas e digitais, ao entrar em contato com água, possibilitando diferenciar um chuvisco de uma tempestade. A leitura digital irá identificar a presença de água sob as hastes metálicas do sensor, alternando entre 0 e 1, enquanto o valor analógico permite analisar a intensidade, variando de 0 á 4095. A pinagem do componente será divida da seguinte maneira:
Encaixe os pinos GND e VCC nas fileiras de alimentação do Protoboard, o terminal D0 do sensor na porta digital D12 e o A0 na porta D35. A leitura analógica será limitada a alguns terminais ao acionar o módulo Wi-Fi, sendo essas as portas ADC1 32, 33, 34, 35, 36 e 39. Como a largura de um único protoboard mostra-se insuficiente para acoplar um ESP32, recomendamos a junção de duas placas.
Os valores do sensor serão interpretados de forma decrescente, ou seja, quanto menor a leitura analógica, maior será o volume da chuva. O funcionamento do sensor será avaliada através do seguinte exemplo:
/* Projeto Curto Circuito - ESP32: Sensor de Chuva */
/*----Sensor de Chuva----*/
int pino_d = 12; /* Pino D12 do ESP32 ligado ao D0 do sensor */
int pino_a = 35; /* Pino D35 do ESP32 ligado ao A0 do sensor */
int val_d = 0; /* Armazena leitura do pino digital */
int val_a = 0; /* Armazena leitura do pino analógico */
/*---- LED----*/
int pin = 2; /* RGB Vermelho pino D2 do ESP32 */
int pin2 = 4; /* RGB Azul pino D4 do ESP32 */
void setup()
{
Serial.begin(9600);
/* Sensores INPUT */
pinMode(pino_d, INPUT);
pinMode(pino_a, INPUT);
/* LEDs OUTPUT */
pinMode(pin, OUTPUT);
pinMode(pin2, OUTPUT);
}
void loop()
{
/* Armazena os valores de leitura */
val_a = analogRead(pino_a);
/* Se a leitura analógica for menor que 300 */
if ( val_a < 1000)
{ /* Chuva intensa */
digitalWrite(pin, 0); /* Desliga */
digitalWrite(pin2, 1); /* Liga */
Serial.println("Chuva Intensa");
Serial.println(val_a );
}
/* Se a leitura analógica for menor que 500 e maior que 300 */
if (val_a <= 3000 && val_a >= 1000)
{ /* Chuva moderada */
digitalWrite(pin, 1); /* Liga */
digitalWrite(pin2, 1); /* Liga */
Serial.println("Chuva Moderada ou Chuvisco");
Serial.println(val_a );
}
/* Se a leitura analógica for maior que 500 */
if ( val_a > 4000)
{ /* Sem previsão de Chuva */
digitalWrite(pin, 1); /* Liga */
digitalWrite(pin2, 0); /* Desliga */
Serial.println("Sem previsão de chuva");
Serial.println(val_a );
}
}
Sensor BME 280
O BME 280 lida com leituras referentes à Pressão atmosférica, Altitude, Umidade e Temperatura. Esse sensor opera com um consumo de energia baixo, apenas 3.3 V, sendo uma opção simples e econômica na coleta de dados barométricos e meteorológicos. A pinagem do componente apresenta-se como:
Conecte o pino SCK na porta digital D21 e SDA na porta digital D22. GND e VCC nos terminais de alimentação do protoboard.
Para auxiliar na construção do projeto recomenda-se adicionar ao menos uma biblioteca, no caso do exemplo a seguir, aderimos a opção “Adafruit BME280 Library” , que pode ser facilmente instalada através do Gerenciador de Bibliotecas do Arduino IDE.
Os exemplo de programação serão divididos entre dois modelos de interface, o I2C, que utiliza apenas 2 pinos de comunicação, e SPI, com 4 pinos. No caso do componente utilizado nesse post, utilizaremos a interface I2C, com endereço 0x76 ou 0x77.
Utilize a programação abaixo para testar o funcionamento do sensor, caso haja algum problema com o funcionamento, substitua o valor de endereço (presente na função bme.begin(0x76)), e pressione o botão RST.
/* Projeto Curto Circuito - ESP32: Sensor BME280 */
/*----Bibliotecas---- */
#include <Wire.h>
#include "Adafruit_BME280.h"
/*----Configurações Sensores I2C----*/
Adafruit_BME280 bme;
#define SEALEVELPRESSURE_HPA (1013.25)
void getValues(void);
void setup()
{
Serial.begin(115200);
Serial.println("Programa Iniciado");
bool status; /* Cria uma variável status de funcionamento do sensor */
status = bme.begin(0x76); /* Endereço 0x77 ou 0x76 */
if (!status)
{ /* Caso não seja identificado */
Serial.println("Sensor Inexistente, verifique as configurações!");
while (1);
}
delay(1000);
}
void loop()
{
getValues();
delay(3000);
}
void getValues()
{
/* Leitura da Temperatura */
Serial.print("Temperatura = ");
Serial.print(bme.readTemperature()); /* Leitura de temperatura */
Serial.println(" ℃"); /* Celsius */
/* Leitura da Pressão */
Serial.print("Pressão = ");
Serial.print(bme.readPressure() / 100.0F); /* Leitura de Pressão */
Serial.println(" Pa"); /* Pascal */
/* Leitura da Altitude */
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));/* Leitura de altitude */
Serial.println(" m"); /* Metros */
/* Leitura de Umidade */
Serial.print("Umidade = ");
Serial.print(bme.readHumidity());/* Leitura Umidade */
Serial.println(" %"); /* Porcentagem */
Serial.println();
}
A função #"Adafruit_BME280.h" inclui a biblioteca na programação, adicionando alguns comandos como bme.readTemperature(), aplicado a leitura da temperatura, ou bme.readHumidity(), umidade. As leituras de pressão variam de acordo com a altitude e as condições de temperatura no ar, quanto maior for a altitude em relação ao mar, menor será a pressão. A proporção para avaliar a leitura com o nível do mar poderá ser dada por meio da seguinte tabela:
A leitura da altitude será realizada através do comando bme.readAltitude(SEALEVELPRESSURE_HPA), que irá utilizar o valor armazenado na variável SEALEVELPRESSURE_HPA na realização de um cálculo simples de conversão, exibindo assim os resultados coletados em metros.
Sensor Luminosidade Ultra Violeta
O sensor Ultravioleta lida com a leitura da tensão de saía, que varia de acordo com a luminosidade UV aplica sob o mesmo. Nesse projeto, será utilizado na analise da intensidade de radiação solar, indicando possíveis riscos a saúde. A pinagem do componente será distribuída da seguinte maneira:
O terminal VIN deverá manter-se desconectado, os pinos de alimentação na fileira 3,3V e GND do Protoboard, OUT no pino VP, e EN no pino D34.
A lógica de programação atribuída ao sensor será construía com base no índice Ultravioleta (IUV), padronizado pela Organização Mundial de Saúde em 1994, que refere-se á níveis internacionais de medida, para avaliar a radiação solar na superfície da terra, indicando possíveis riscos e danos a saúde de acordo com os valores que variam de 0 á 11.
No exemplo abaixo, utilizaremos a mistura de cores presente em um LED RGB para indicar a intensidade da radiação, juntamente à leitura indicada no Monitor Serial do Arduino IDE.
/* Projeto Curto - ESP32 : Sensor UV -------- */
int UVOUT = 36; /* Pino D36 do ESP32 conetado ao Out do sensor */
int REF = 34; /* Pino D34 do ESP32 conectado ao EN do sensor */
/*-------- LEDs e Contador-------- */
int LED = 2; /* Led do ESP */
int RED = 23; /* LED RGB pino vermelho */
int BLUE = 5; /* LED RGB pino azul */
int GREEN = 4; /* LED RGB pino green */
void setup()
{
Serial.begin(115200);
pinMode(LED, OUTPUT);
pinMode(RED, OUTPUT);
pinMode(BLUE, OUTPUT);
pinMode(GREEN, OUTPUT);
}
void loop()
{
int uvLevel = analogRead(UVOUT); /* Armazena a leitura analógica do pino OUT */
int refLevel = analogRead(REF); /* Armazena a leitura analógica do pino EN */
/* Use 3.3V como referencia no calculo de tensão */
float outputVoltage = 3.3 / refLevel * uvLevel; /* Indica a tensão de saída do sensor */
float uvIntensity = map(outputVoltage, 0.99, 2.9, 0.0, 15.0); /* Intensidade raios UV */
Serial.print(" Intensidade UV: ");
Serial.println(uvIntensity);
if (uvIntensity >= 0 && uvIntensity <= 2)
{ /* Intensidade Baixa: Verde */
digitalWrite(RED, 0);
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 1);
}
if (uvIntensity >= 3 && uvIntensity < 5)
{ /* Intensidade Moderada: Amarelo */
digitalWrite(RED, 1);
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 1);
}
if (uvIntensity == 6 || uvIntensity == 7)
{ /* Intensidade Alta: Laranja (branco) */
digitalWrite(RED, 1);
digitalWrite(BLUE, 1);
digitalWrite(GREEN, 1);
}
if (uvIntensity >= 8 && uvIntensity < 10)
{ /* Intensidade Elevada: Vermelho */
digitalWrite(RED, 1);
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 0);
}
if (uvIntensity >= 11)
{ /* Intensidade Elevada: Violeta */
digitalWrite(RED, 1);
digitalWrite(BLUE, 1);
digitalWrite(GREEN, 0);
}
}
A lógica de programação será baseada, principalmente, na leitura da tensão de saída do sensor, por isso, a variável "outputVoltage" irá utilizar 3.3 como referência no calculo, pois a tensão de saída será o valor de alimentação dividido pela leitura analógica nos pinos D36 e D34.
float outputVoltage = 3.3 / refLevel * uvLevel;
O resultado do cálculo será aplicado a função map, presente na variável "uvIntensity", que será utilizado para determinar a intensidade dos raios UV, de acordo com o mapeamento dos valores de "outputVoltage".
float uvIntensity = map(outputVoltage, 0.99, 2.9, 0.0, 15.0);
A função map irá avaliar a variável "outputVoltage", mapeando a leitura de acordo com os intervalos determinados, que, no caso da programação foram definidas em quatro variáveis, 0.99(mínimo) ,2.9 (máximo), 0.0 (mínimo), 15.0 (máximo), sendo elas duas entradas (in) e duas saídas (out). Segundo o site Arduino.cc, a lógica matemática por trás da função será similar a uma regra de três. Para compreender essa lógica de forma mais simples, observe a fórmula completa no exemplo abaixo:
long map(long x, long in_min,long in_max, long out_min, long out_max){ return (x - in_min)*(out_max - out_min) / (in_max - in_min)+ out_min; }
Suponha que a leitura em outputVoltage seja igual a 2, se aplicarmos a forma apresentada acima: return( 2 - 0,99) * (15,0 - 0,0) / (2,9 - 0,99) + 0,0 = 7,9 , Como o resultado encontra-se acima de 5, a intensidade dos raios UV será considerada como alta. As cores no LED serão equivalentes ao alerta, com exceção da cor Laranja, que será demonstrada como um cor branca.
IBM Cloud: Conectando ao Servidor
O armazenamento de informações na nuvem requer uma comunicação entre o ESP32 e um host particular, nesse caso, o servidor será construído através da IBM Cloud, pois esta ferramenta possui um vinculo direto com o editor de fluxo Node-RED, além de deixar a disposição diversos recursos que facilitam o desenvolvimento de plataformas automatizadas. A construção do servidor requer uma conta de usuário no site bluemix.net, e a escolha de uma plataforma de desenvolvimento em Catálogo, que nesse caso, será a opção "Internet of Things Platform Starter".
Nomeie o aplicativo, e procure manter o plano selecionado em Lite caso deseje desenvolver o projeto de forma gratuita. Em Conexões, acesse a plataforma Watson IoT Platform, que servirá como ferramenta principal na inclusão de dispositivos eletrônicos, permitindo que a leitura e controle de componentes como o ESP32, sejam armazenadas nos servidores da IBM.
No menu lateral da plataforma Watson procure por "Aplicativos", e utilize a opção "Gerar chave API". Esta ferramenta irá prover um Token, que será utilizado como medida de segurança, servindo como um código de autenticação na conexão entre o ESP32 e o IBM.
Acesse o menu "Dispositivos", e procure a opção "Incluir Dispositivo". Esta opção irá construir um tipo de objeto virtual, e através de algumas configurações na própria programação, possibilita a coleta de informação diretamente no componente real, no caso desse projeto, irá coletar a transmissão de dados presente no ESP32. Nomeie o tipo, crie uma identificação (ID) exclusiva para o componente, e insira o Token de Autenticação, não será preciso configurar os metadados.
Programação
O status do componente será exibido na lista de dispositivos, e permanecerá desconectado até que a programação presente no ESP32 esteja ajustada com os seguintes parâmetros:
/* Projeto Curto Circuito – Estação Meteorológica: IBM Watson */
/*-------- Bibliotecas -----------*/
#include <WiFi.h>
#include <Wire.h>
#include <PubSubClient.h> /* https://github.com/knolleary/pubsubclient/releases/tag/v2.3 */
#include <ArduinoJson.h> /* https://github.com/bblanchon/ArduinoJson/releases/tag/v5.0.7 */
#include "Esp32MQTTClient.h"
/* ------ Configurações WiFi -------- */
const char* ssid = "Nome_da_rede";
const char* password = "Senha";
/*-------- Conexão IBM-ESP32 ----------- */
#define ORG "ORG" /* ID de organização */
#define DEVICE_TYPE "Componente" /* Insira o nome do componente */
#define DEVICE_ID "ID do componente" /* Insira o ID */
#define TOKEN "Token de autenticação"/* Insira o Token */
/*-------- Comunicação IOT (Não mexer)-------- */
char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;
const char eventTopic[] = "iot-2/evt/status/fmt/json";
const char cmdTopic[] = "iot-2/cmd/led/fmt/json";
/*-------- Sensor de Chuva-------- */
#define pino_d 14 /* Pino digital D14 do ESP32 */
#define pino_a 35 /* Pino analógico D35 do ESP32 */
int val_a = 0; /* Chuva leitura analógica */
int val_d = 0; /* Chuva leitura digital */
int result = 0 ; /* Lógica que transforma a leitura do sensor em porcentagem. */
/*-------- Sensor BME280 -------- */
#include "Adafruit_BME280.h" /* Biblioteca Adafruit BME280 */
Adafruit_BME280 bme; /* Configuração I2C */
/*-------- Sensor UV -------- */
int UVOUT = 36; /* Pino Out D36 do ESP32 */
int REF = 34; /* Pino EN D34 do ESP32 */
/*-------- LEDs e Contador--------*/
int LED = 2; /* Led do ESP */
int RED = 23; /* LED RGB pino vermelho */
int BLUE = 5; /* LED RGB pino azul */
int GREEN = 4; /* LED RGB pino green */
int contagem = 0; /* Contagem crescente */
WiFiClient wifiClient;
void callback(char* topic, byte* payload, unsigned int payloadLength)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
if ((char)payload[0] == '0')
{ /* Se receber o caractere 0 */
digitalWrite(LED, LOW); /* Desliga o LED */
Serial.println("LOW");
}
if ((char)payload[0] == '1')
{ /* Se receber o caractere 1 */
digitalWrite(LED, HIGH); /* Liga LED */
Serial.println("HIGH");
}
}
PubSubClient client(server, 1883, callback, wifiClient);
void setup()
{
Serial.begin(115200);
pinMode(LED, OUTPUT);
pinMode(RED, OUTPUT);
pinMode(BLUE, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(UVOUT, INPUT);
pinMode(REF, INPUT);
client.setCallback(callback);
bool status;
status = bme.begin(0x76); /* Avalia a conexão do BME */
if (!status)
{ /* Se estiver desconectado */
Serial.println("BME280 não localizado, confira a pinagem do sensor!");
while (1);
}
/*---------Quando o sensor BME estiver conectado----------- */
wifiConnect(); /* Direciona ao void wifiConnect */
mqttConnect(); /* Direciona ao void mqttConnect */
}
void wifiConnect()
{ /* Funções conectar ao Wi-Fi */
Serial.print("Conectando a rede:");
Serial.print(ssid); /* Indica a rede Wi-Fi ao qual irá se conectado */
WiFi.begin(ssid, password); /* Conecta ao ssid e o password configurado */
while (WiFi.status() != WL_CONNECTED)
{ /* Enquanto o Wi-Fi estiver desconectado */
delay(500); /* Aguarda meio segundo */
Serial.print(".");
}
Serial.print("Rede Wi-Fi Conectada, Endereço de IP: ");
Serial.println(WiFi.localIP()); /* Indica o endereço de IP */
}
void mqttConnect()
{ /* Funções conectar ao servidor */
if (!!!client.connected())
{ /* Se não houver conexão com o servidor */
Serial.print("Reconectando ao servidor:");
Serial.println(server); /* Indica o endereço do servidor */
while (!!!client.connect(clientId, authMethod, token) )
{
Serial.print(".");
delay(500);
}
if (client.subscribe(cmdTopic))
{ /* Se conseguir se Conectar ao cmdTopic */
Serial.println("OK"); /* Escreve OK no monitor serial */
}
else
{
Serial.println("Erro"); /* Escreve erro no monitor serial */
}
}
}
void loop()
{
if (!client.loop())
{ /* Se Desconectar do Servidor */
mqttConnect(); /* Retorna a função mqttConnect */
}
float h = bme.readHumidity(); /* Armazena os valor de leitura da Umidade */
float t = bme.readTemperature(); /* Armazena os valor de leitura da Temperatura */
float p = bme.readPressure(); /* Armazena os valores de leitura da Pressão */
float a = bme.readAltitude(1013.25); /* Armazena os valores de leitura da Altitude */
val_a = analogRead(pino_a) ; /* Armazena os valores analógicos do sensor de chuva */
p = p / 100.0F; /* Realiza um calculo que ajusta o valor de p */
/* Cria uma variável que coleta a leitura do sensor de chuva */
int result = 0; /* Cria uma variável do tipo inteira */
result = (val_a * 100) / 4095; /* Transforma o valor em porcentagem */
/* ----- As String abaixo serão responsáveis por enviar mensagens ao servidor ------ */
String payload = "{\"d\":{\"adc\":"; /* Inicia Payload */
payload += contagem; /* Inclui o valor de contagem */
payload += "}}"; /* Finaliza a função */
Serial.print("Contagem: "); Serial.println(payload); /* Escreve o valor no monitor serial */
client.publish(eventTopic, (char*) payload.c_str() );/* Publica Payload */
delay(100); /* Aguarda 100 milissegundos */
String payload2 = "{\"d\":{\"umi\":"; /* Inicia Payload2 */
payload2 += h; /* Inclui o valor de h */
payload2 += "}}"; /* Finaliza a função */
Serial.print(" Umidade: "); Serial.println(payload2); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload2.c_str() );/* Publica Payload2 */
delay(100); /* Aguarda 100 milissegundos */
String payload3 = "{\"d\":{\"tem\":"; /* Inicia Payload3 */
payload3 += t; /* Inclui o valor de t */
payload3 += "}}"; /* Finaliza a função */
Serial.print(" Temperatura: "); Serial.println(payload3);/* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload3.c_str() ); /* Publica Payload3 */
delay(100); /* Aguarda 100 milissegundos */
String payload4 = "{\"d\":{\"pre\":"; /* Inicia Payload4 */
payload4 += p; /* Inclui o valor de p */
payload4 += "}}"; /* Finaliza a função */
Serial.print(" Pressão: "); Serial.println(payload4); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload4.c_str() ); /* Publica Payload4 */
delay(100); /* Aguarda 100 milissegundos */
String payload5 = "{\"d\":{\"alt\":"; /* Inicia Payload5 */
payload5 += a; /* Inclui o valor de a */
payload5 += "}}"; /* Finaliza a função */
Serial.print(" Altitude: "); Serial.println(payload5); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload5.c_str() ); /* Publica Payload5 */
delay(100); /* Aguarda 100 milissegundos */
String payload6 = "{\"d\":{\"chu\":"; /* Inicia Payload6 */
payload6 += result; /* Inclui o valor de result */
payload6 += "}}"; /* Finaliza a função */
Serial.print(" Chuva: "); Serial.println(payload6); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload6.c_str() ); /* Publica Payload5 */
delay(100); /* Aguarda 100 milissegundos */
contagem ++; /* Contagem + 1 */
delay(1000); /* Aguarda 1 segundo */
uv_test(); /* Direciona ao void uv_test */
}
void uv_test()
{
int uvLevel = analogRead(UVOUT); /* Armazena a leitura analógica do pino OUT */
int refLevel = analogRead(REF); /* Armazena a leitura analógica do pino EN */
/* Use o valor de 3.3V como referencia no calculo de tensão */
float outputVoltage = 3.3 / refLevel * uvLevel; /* Indica a tensão de saída do sensor */
float uvIntensity = map(outputVoltage, 0.99, 2.9, 0.0, 15.0); /* Intensidade raios UV */
String payload7 = "{\"d\":{\"uvl\":"; /* Inicia Payload7 */
payload7 += uvLevel; /* Inclui o valor de uvLevel */
payload7 += "}}"; /* Finaliza a função */
Serial.print(" Level: "); Serial.println(payload7); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload7.c_str() ); /* Publica Payload7 */
delay(100);
String payload8 = "{\"d\":{\"volt\":"; /* Inicia Payload8 */
payload8 += outputVoltage; /* Inclui o valor de outputVoltage */
payload8 += "}}"; /* Finaliza a função */
Serial.print(" Tensao: "); Serial.println(payload8); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload8.c_str() ); /* Publica Payload8 */
delay(100);
String payload9 = "{\"d\":{\"uvi\":"; /* Inicia Payload9 */
payload9 += uvIntensity; /* Inclui o valor de uvIntensity */
payload9 += "}}"; /* Finaliza a função */
Serial.print(" Intensidade UV: "); Serial.println(payload9); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload9.c_str() ); /* Publica Payload8 */
Serial.println(); /* Pula uma linha */
delay(1000); /* Aguarda 1 segundo */
if (uvIntensity >= 0 && uvIntensity <= 2)
{ /* Intensidade Baixa: Verde */
digitalWrite(RED, 0);
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 1); /* Liga LED VERDE */
}
if (uvIntensity >= 3 && uvIntensity < 5)
{ /* Intensidade Moderada: Amarelo */
digitalWrite(RED, 0);
digitalWrite(BLUE, 1); /* Liga LED AZUL */
digitalWrite(GREEN, 1); /* Liga LED VERDE */
}
if (uvIntensity == 6 || uvIntensity == 7)
{ /* Intensidade Alta: Laranja */
digitalWrite(RED, 1); /* Liga LED VERMELHO */
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 1); /* Liga LED VERDE */
}
if (uvIntensity >= 8 && uvIntensity < 10)
{ /* Intensidade Elevada: Vermelho */
digitalWrite(RED, 1); /* Liga LED VERMELHO */
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 0);
}
if (uvIntensity >= 11)
{ /* Intensidade Elevada: Violeta */
digitalWrite(RED, 1); /* Liga LED VERMELHO */
digitalWrite(BLUE, 1); /* Liga LED AZUL */
digitalWrite(GREEN, 0);
}
}
String payload2 = "{\"d\":{\"umi\":"; /* Inicia Payload2 */
payload2 += h; /* Inclui o valor da umidade */
payload2 += "}}"; /* Finaliza a função */
client.publish
(
eventTopic, (char*) payload2.c_str()
); /* Publica Payload2 */
A função client.publish será responsável por transmitir as informações coletadas ao servidor, no caso do exemplo será transmitida a leitura da umidade. A mensagem será composta por duas variáveis, o eventTopic[], que foi declarado no inicio da programação com o cógido "iot-2/evt/status/fmt/json", e o payload2, que irá compor a mensagem "{\d:\umi\h}}". A junção das variáveis irá construir um evento para a transmissão da leitura de "h" (leitura da umidade), em formato JSON.
As opções de TSL implicam na segurança do componente, normalmente, alguns pacotes de desenvolvimento gratuito limitam a conexão as opções Autenticação por Token ou Opcional. O modo que certamente irá estabelecer uma conexão rápida será a TSL Opcional, pois este não requer qualquer chave de segurança no circuito, apresentando-se como uma das opções mais inseguras, porém, com total certeza de conexão.
Após alterar o tipo de TSL, o componente adicionado deverá conectar-se ao servidor, indicando o horário de conexão em "Identidade". Após certificar-se sobre a conexão do componente, acesse o painel de aplicativos e clique na URL do projeto.
O link será direcionado ao editor Node-RED, se este for o primeiro acesso a página, será possível criar um login de acesso, limitando a edição dos fluxos em alguns usuários específicos. O Navegador será dividido em três partes principais:
Ao abrir o Node-RED, clique no botão e selecione a opção Manage Palette, no menu Install escreva “dashboard”, e instale o conjunto node-red-dasboard.
Um novo conjunto será adicionado as opções de nós, com a finalidade de personalizar a página de controle principal do navegador. A coleta de informações presente no ESP32, será estabelecida por um fluxo de comunicação entre um nó IBM IoT Input e um Debug.
Nas opções de configuração do nó IBM IoT ajuste os seguintes parâmetros:
A opção "Device Event" será utilizada no recebimento de mensagens (Payload) provenientes do ESP32, "Event" irá filtrar a leitura do nó, direcionando-a a algum um evento específico da programação, no caso desse exemplo, o sinal "+" será aplicado a coleta de quaisquer informações. As demais opções serão configuradas tal qual fôra apresentado nos parâmetros "Comunicação IOT ".
Inclua um nó Numeric (presente em Dashboard) e procure construir o seguinte fluxo.
Clique em Deploy, e selecione a opção Debug para visualizar as mensagens recebidas.
Adicione dois nós Gauge (do conjunto Dashboard), aplicados a leitura de Umidade e Temperatura. Nas opções de configuração será necessário ajustar um ponto mínimo e máximo de cada leitura. a Umidade será 0 á 100, pois sua grandeza será demonstrada em porcentagem (%), enquanto a temperatura poderá ser ajustada de forma livre. No caso desse post, por exemplo, avaliamos o tipo de clima da região Sudeste do Brasil, e determinamos um de mínimo de -10° e máximo de 40°C. As demais variáveis serão opcionais, servindo apenas para configurar a estética da ferramenta.
A opção Group servirá para separar os componentes em conjuntos, na versão dashboard do navegador, cada grupo será exibido em colunas individuais, auxiliando na organização visual das ferramentas.
Cada fluxo de leitura será composto por um nó Function, e a função "return" será escrita de forma similar, alterando apenas a última palavra de cada um, como mostra o exemplo abaixo.
Conecte os nós ao fluxo configurado anteriormente, demonstrado na imagem abaixo. Como a opção "Event", do nó IBM IoT, não foi direcionada a nenhum evento específico, então, essa ferramenta será capaz de coletar quaisquer informações presente no ESP32.
Na avaliação do sensor de chuva utilizaremos outro modelo de nó Gauge, colocando a opção Type como Nível, e, assim como a umidade, configurando os pontos mín/máx de leitura da intensidade em 0 e 100 %. Adicione um nó Function, e configure como mostra a imagem a seguir, alterando apenas a última palavra do comando para "chu". Conecte tudo ao IBM IoT.
As leituras de Pressão e Altitude serão impressas em gráficos de linhas, portanto, adicione dois nós Chart, das opções Dashboard.
Nas configurações procure manter os pontos mínimo e máximo em branco, para que os pontos de ajuste do gráfico se ajustem automaticamente aos valores coletados. Escolha o tipo de medição como "Line Chart", e o formato em "x-axis Label" como HH:MM:AA.
Configure o nó Function de cada sensor alterando as últimas linhas para "pre" e "alt", e construa um fluxo com as respectivas ferramentas Chart.
Na leitura da intensidade de raios Ultravioletas, adicione três blocos Function e configure os seguintes endereços:
Conecte três nós Text Imput, do menu Dashboard, conectando-os em cada Function de leitura UV. Não haverá necessidade de configurar as opções desses nós, pois, este irá exibir informação com base nos valores fornecidos pela função Return.
Construa um fluxo conectando todas as variáveis de leitura ao IBM IoT Input.
Por fim, a programação possui dois tipos de LED, um RGB que indica a intensidade dos raios UV, e um para controlar o acionamento, o D2 presente no próprio ESP32. O controle do LED de teste será estabelecido por um nó Switch, do conjunto Dashboard.
Nas opções do Switch, será necessário ajustar o tipo de mensagem como String, com valores 1 (HIGH) e 0 (LOW), e em Topic escreva “led”.
O controle de componentes requer a construção de um novo fluxo de comunicação, portanto, adicione um nó IBM IoT Output e um Debug.
Nas configurações do nó IBM, a opção Type será alterada para Device Command, utilizada no envio de mensagens ao circuito, controlando funções no ESP32, enquanto o comando Type direciona a leitura através da opção "led".
Construa um fluxo entre os blocos, e pressione o botão Deploy para intalar as atualizações do Node-RED.
Caso queira ajustar a paleta de cores do navegador, título, e opções de layout, retorne a página de programação do Node-RED, e clique no botão dashbord
Acesse o navegador “/ui” para visualizar o layout e funcionamento das ferramentas.
https://______.mybluemix.net/ui
Estação em modo Econômico
Nas postagens anteriores apresentamos o comando Deep Sleep, que possibilita desligar praticamente todas as funções principais de um ESP32, mantendo apenas alguns periféricos de memória e o coprocessador em modo ULP (Ultra Low Power). Manter o sistema em Stand-by torna o consumo de energia consideravelmente menor, e, para tornar o projeto mais sustentável e econômico, iremos adicionar tal função a programação, com o objetivo de determinar horários de descanso para o ESP32 e ajustar o despertar do sistema de forma automática e manual. A programação abaixo irá coletar as informações de leitura dos sensores, armazenando-as no servidor durante o período de 10 segundos, após esse prazo, entrará em repouso por 30 segundos, e o único meio de interromper esse loop temporal será pressionando o sensor capacitivo T2 (pino D2), para acionar o despertar antes do tempo.
/* Projeto Curto Circuito – ESP32: Estação Meteorológica em DEEP SLEEP */
/* ------ Bibliotecas -------- */
#include <WiFi.h>
#include <Wire.h>
#include <PubSubClient.h> /* https://github.com/knolleary/pubsubclient/releases/tag/v2.3 */
#include <ArduinoJson.h> /* https://github.com/bblanchon/ArduinoJson/releases/tag/v5.0.7 */
#include <esp_deepsleep.h>
#include "Esp32MQTTClient.h"
/* ------ Configurações WiFi -------- */
const char* ssid = "Nome_da_rede";
const char* password = "Senha";
/*-------- Conexão IBM-ESP32 ----------- */
#define ORG " Insira o ORG" /* seis primeiros caracteres do servidor */
#define DEVICE_TYPE "Insira o nome do Componente" /* Nome dado ao componente no servidor Watson */
#define DEVICE_ID "Insira o ID do componente" /* ID dado ao componente no servidor Watson */
#define TOKEN "Token de autenticação" /* Insira a Chave API */
/*-------- Comunicação IOT -------- */
char server[] = ORG ".messaging.internetofthings.ibmcloud.com";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;
const char eventTopic[] = "iot-2/evt/status/fmt/json";
const char cmdTopic[] = "iot-2/cmd/led/fmt/json";
/*-------- Sensor de Chuva-------- */
#define pino_d 14 /* Pino digital D14 do ESP32 */
#define pino_a 35 /* Pino analógico D35 do ESP32 */
int val_a = 0; /* Armazenar leitura analógica */
int val_d = 0; /* Armazenar leitura digital */
int result = 0 ; /* Transforme a leitura do sensor em porcentagem. */
/*-------- Sensor BME280 -------- */
#include "Adafruit_BME280.h" /* Biblioteca Adafruit BME280 */
Adafruit_BME280 bme; /* I2C */
/*-------- Memória RTC-------- */
RTC_DATA_ATTR int tempo; /* Armazena os valores de tempo no RTC. */
RTC_DATA_ATTR int tempo2; /* Armazena os valores de tempo2 no RTC. */
/*-------- Sensor Capacitivo-------- */
#define Threshold 40 /* Define a sensibilidade do sensor capacitivo. */
touch_pad_t touchPin;
/*-------- Sensor UV -------- */
int UVOUT = 36; /* Pino Out D36 (VP) do ESP32 */
int REF = 34; /* Pino EN D34 do ESP32 */
/*-------- LEDs e Contador-------- */
int LED = 2; /* Led D2 do ESP32 */
int RED = 23; /* RGB pino vermelho D32 do ESP32 */
int BLUE = 5; /* RGB pino azul D05 do ESP32 */
int GREEN = 4; /* RGB pino green D4 do ESP3 */
WiFiClient wifiClient; /* Configura WiFi Client */
void callback(char* topic, byte* payload, unsigned int payloadLength)
{ /* Função de retorno, para controlar o ESP32 por meio da plataforma NODE-RED */
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
if ((char)payload[0] == '0')
{ /* Se receber o caractere 0 */
digitalWrite(LED, LOW); /* Desliga o LED */
Serial.println("LOW");
}
if ((char)payload[0] == '1')
{ /* Se receber o caracter 1 */
digitalWrite(LED, HIGH); /* Liga LED */
Serial.println("HIGH");
}
}
PubSubClient client(server, 1883, callback, wifiClient);
void wakeup_touchpad()
{ /* Função para configurar o despertar do ESP32 através de um pino Touch */
touch_pad_t pin;
touchPin = esp_sleep_get_touchpad_wakeup_status(); /* Função touchPin */
}
void callback2() {}
void setup()
{
wakeup_touchpad(); /* Chama a função de configuração do touch */
Serial.begin(115200); /* Taxa de transmissão */
pinMode(LED, OUTPUT);
pinMode(RED, OUTPUT);
pinMode(BLUE, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(UVOUT, INPUT);
pinMode(REF_3V3, INPUT);
client.setCallback(callback);
bool status; /* Cria uma variável de leitura bool */
status = bme.begin(0x76); /* Configura o enderelo do BME como 0x76 */
if (!status)
{ /* Verifiva o status de conexão do sensor BME */
Serial.println("BME280 não localizado, confira a pinagem do sensor!"); /* se estiver desconectado */
while (1);
}
delay(100);
touchAttachInterrupt(T2, callback2, Threshold); /* Determina que o pino touch será o T2, terá o valor de sensibilidade declarado em Threshold. */
esp_sleep_enable_touchpad_wakeup(); /* Habilita o despertar do ESP32 por sensor touch */
esp_sleep_enable_timer_wakeup(30000000); /* Determina que a cada 30 segundos o ESP32 irá despertar */
tempo2 += 10; /* Aumenta em 10 o valor de tempo2 */
wifiConnect(); /* Chama a função de conexão do Wi-Fi */
mqttConnect(); /* Chama a função de com o servidor */
}
void wifiConnect()
{ /* Funções para conectar ao Wi-Fi */
Serial.print("Conectando a rede:");
Serial.print(ssid); /* Indica a rede Wi-Fi ao qual irá se conectado */
WiFi.begin(ssid, password); /* Conecta ao ssid e o password configurado */
while (WiFi.status() != WL_CONNECTED)
{ /* Enquanto o Wi-Fi estiver desconectado */
delay(500); /* Aguarda meio segundo */
Serial.print(".");
}
Serial.print("Rede Wi-Fi Conectada, Endereço de IP: ");
Serial.println(WiFi.localIP()); /* Indica o endereço de IP */
}
void mqttConnect()
{ /* Funções para conectar ao servidor */
if (!!!client.connected())
{ /* Se não houver conexão com o servidor */
Serial.print("Reconectando ao servidor:");
Serial.println(server); /* Indica o endereço do servidor */
while (!!!client.connect(clientId, authMethod, token) )
{
Serial.print(".");
delay(500);
}
if (client.subscribe(cmdTopic))
{ /* Se conseguir se Conectar ao cmdTopic */
Serial.println("OK"); /* Escreve OK no monitor serial */
}
else
{
Serial.println("Erro"); /* Escreve erro no monitor serial */
}
}
}
void loop() {
if (!client.loop())
{
mqttConnect(); /* Tenta reconectar ao servidor */
}
if (tempo == tempo2)
{ /* Se a contagem de tempo for igual a variável tempo2 */
delay(1);
esp_deep_sleep_start(); /* Inicia o modo de descanso Deep Sleep */
}
float h = bme.readHumidity(); /* Armazena os valor de leitura da Umidade */
float t = bme.readTemperature(); /* Armazena os valor de leitura da Temperatura */
float p = bme.readPressure(); /* Armazena os valores de leitura da Pressão */
float a = bme.readAltitude(1013.25); /* Armazena os valores de leitura da Altitude */
val_a = analogRead(pino_a) ; /* Armazena os valores analógicos do sensor de chuva */
p = p / 100.0F; /* Realiza um calculo que ajusta o valor de p */
/* Cria uma variável que coleta a leitura do sensor de chuva */
int result = 0; /* Cria uma variável do tipo inteira */
result = (val_a * 100) / 4095; /* Transforma o valor em porcentagem */
/* ----- As String abaixo serão responsáveis por enviar mensagens ao servidor ------ */
String payload = "{\"d\":{\"adc\":"; /* Inicia Payload */
payload += contagem; /* Inclui o valor de contagem */
payload += "}}"; /* Finaliza a função */
Serial.print("Contagem: "); Serial.println(payload); /* Escreve o valor no monitor serial */
client.publish(eventTopic, (char*) payload.c_str() );/* Publica Payload */
delay(100); /* Aguarda 100 milissegundos */
String payload2 = "{\"d\":{\"umi\":"; /* Inicia Payload2 */
payload2 += h; /* Inclui o valor de h */
payload2 += "}}"; /* Finaliza a função */
Serial.print(" Umidade: "); Serial.println(payload2); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload2.c_str() );/* Publica Payload2 */
delay(100); /* Aguarda 100 milissegundos */
String payload3 = "{\"d\":{\"tem\":"; /* Inicia Payload3 */
payload3 += t; /* Inclui o valor de t */
payload3 += "}}"; /* Finaliza a função */
Serial.print(" Temperatura: "); Serial.println(payload3);/* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload3.c_str() ); /* Publica Payload3 */
delay(100); /* Aguarda 100 milissegundos */
String payload4 = "{\"d\":{\"pre\":"; /* Inicia Payload4 */
payload4 += p; /* Inclui o valor de p */
payload4 += "}}"; /* Finaliza a função */
Serial.print(" Pressão: "); Serial.println(payload4); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload4.c_str() ); /* Publica Payload4 */
delay(100); /* Aguarda 100 milissegundos */
String payload5 = "{\"d\":{\"alt\":"; /* Inicia Payload5 */
payload5 += a; /* Inclui o valor de a */
payload5 += "}}"; /* Finaliza a função */
Serial.print(" Altitude: "); Serial.println(payload5); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload5.c_str() ); /* Publica Payload5 */
delay(100); /* Aguarda 100 milissegundos */
String payload6 = "{\"d\":{\"chu\":"; /* Inicia Payload6 */
payload6 += result; /* Inclui o valor de result */
payload6 += "}}"; /* Finaliza a função */
Serial.print(" Chuva: "); Serial.println(payload6); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload6.c_str() ); /* Publica Payload5 */
delay(100); /* Aguarda 100 milissegundos */
tempo++;
delay(1000);
uv_test();
}
void uv_test()
{
int uvLevel = analogRead(UVOUT); /* Armazena a leitura analógica do pino OUT */
int refLevel = analogRead(REF); /* Armazena a leitura analógica do pino EN */
/* Use o valor de 3.3V como referencia para o calculo de tensão */
float outputVoltage = 3.3 / refLevel * uvLevel; /* Indica a tensão de saída do sensor */
float uvIntensity = map(outputVoltage, 0.99, 2.9, 0.0, 15.0); /* Intensidade raios UV */
String payload7 = "{\"d\":{\"uvl\":"; /* Inicia Payload7 */
payload7 += uvLevel; /* Inclui o valor de uvLevel */
payload7 += "}}"; /* Finaliza a função */
Serial.print(" Level: "); Serial.println(payload7); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload7.c_str() ); /* Publica Payload7 */
delay(100);
String payload8 = "{\"d\":{\"volt\":"; /* Inicia Payload8 */
payload8 += outputVoltage; /* Inclui o valor de outputVoltage */
payload8 += "}}"; /* Finaliza a função */
Serial.print(" Tensao: "); Serial.println(payload8); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload8.c_str() ); /* Publica Payload8 */
delay(100);
String payload9 = "{\"d\":{\"uvi\":"; /* Inicia Payload9 */
payload9 += uvIntensity; /* Inclui o valor de uvIntensity */
payload9 += "}}"; /* Finaliza a função */
Serial.print(" Intensidade UV: "); Serial.println(payload9); /* Escreve no monitor serial */
client.publish(eventTopic, (char*) payload9.c_str() ); /* Publica Payload8 */
Serial.println(); /* Pula uma linha */
delay(1000); /* Aguarda 1 segundo */
if (uvIntensity >= 0 && uvIntensity <= 2)
{ /* Intensidade Baixa: Verde */
digitalWrite(RED, 0);
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 1); /* Liga LED VERDE */
}
if (uvIntensity >= 3 && uvIntensity < 5)
{ /* Intensidade Moderada: Amarelo */
digitalWrite(RED, 0);
digitalWrite(BLUE, 1); /* Liga LED AZUL */
digitalWrite(GREEN, 1); /* Liga LED VERDE */
}
if (uvIntensity == 6 || uvIntensity == 7)
{ /* Intensidade Alta: Laranja */
digitalWrite(RED, 1); /* Liga LED VERMELHO */
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 1); /* Liga LED VERDE */
}
if (uvIntensity >= 8 && uvIntensity < 10)
{ /* Intensidade Elevada: Vermelho */
digitalWrite(RED, 1); /* Liga LED VERMELHO */
digitalWrite(BLUE, 0);
digitalWrite(GREEN, 0);
}
if (uvIntensity >= 11)
{ /* Intensidade Elevada: Violeta */
digitalWrite(RED, 1); /* Liga LED VERMELHO */
digitalWrite(BLUE, 1); /* Liga LED AZUL */
digitalWrite(GREEN, 0);
}
}
Ao despertar o sistema do modo Deep Sleep, boa parte das funções como comunicação Wi-F, CPU, e todas as leituras presente no ESP32 serão reiniciadas, e a única forma de manter os dados a salvo será através da construção de uma variável de armazenamento que aloque tais dados em uma memória RTC, como o demonstrado nos comandos RTC_DATA_ATTR int tempo e RTC_DATA_ATTR int tempo2. No caso da programação acima, apenas as variáveis de contagem serão mantidas em RTC, pois, além de as demais leituras já estarem salvas no próprio servidor, o tempo será um ponto importante para o funcionamento do ciclo de descanso do ESP32. O void wakeup_touchpad será utilizado na configuração de um sensor capacitivo, como meio de remover o ESP32 do modo de hibernação. As funções touch_pad_t e esp_sleep_get_touchpad_wakeup_status, irão construir variáveis de leitura aplicada aos pinos capacitivos, determinando que o toque irá influenciar no status da hibernação. O touchAttachInterrupt() configura o pino T2 como um interruptor no processo de despertar do ESP32, utilizando o valor da variável Threshold no ajuste da sensibilidade do sensor. A função esp_sleep_enable_timer_wakeup() determina um intervalo de tempo para despertar o sistema, esse valor será interpretado em microssegundos (1 segundo = 1.000000 microssegundos). E por fim, esp_deep_sleep_start(), inicia o modo de hibernação do ESP32.
Considerações Finais
Ao desbloquear a tela de um smartphone, ou acessar uma rede social qualquer, automaticamente serão exibidas informações referentes as condições climáticas do dia, alertas meteorológicos, e análises barométricas. Esse tipo de informações se apresenta de forma tão sutil em nossa rotina diária, que poucos realmente já se perguntaram o que seria necessário para coletar tais informações. O ESP32 mostrou ser uma das melhores opções para a aplicação dessa problemática em um circuito elétrico, afinal com uma rápida comunicação entre o módulo Wi-Fi e um servidor web particular, construímos uma ferramenta meteorológica completa, capaz de fornecer gráficos e bases para estudos de forma acessível, e, graças ao Node-RED e a IBM Watson, conectar componentes em sistemas IoT, além do desenvolvimento de plataformas supervisórias tornou-se mais simples. E se em algum momento o consumo de energia se apresentou como um problema, o modo de hibernação Deep Sleep estará a disposição, para manter o sistema com um consumo de aproximadamente 150 µA.
Deixaremos anotado como sugestão a mudança de plataforma utilizada neste tutorial, para uma que ainda possibilite a conexão.
Utilizando:
DevKit 4 - ESP VROOM 32 com 38 pinos.
BM280 com 6 conexões.
Informo um erro na parte do BM280 onde o texto " Conecte o pino SCK na porta digital D21 e SDA na porta digital D22. GND e VCC nos terminais de alimentação do protoboard não bate com o desenho de conexões.
A duvida:
Usando o devkit e o Vroom32 acima teria que mudar algo ? (considerando que o BM280 está ok).
Já enverti porta 21 com 22, já mudei de (0x76) para (0x77) e só informa no monitor serial: Sensor inexistente.
Alguma sugestão dos amigos ?
Obrigado.
Neste módulo a saída 21 é referente ao SDA.
A saída 22 é referente ao SCL.
Esse erro pode ser referente ao código do I2C.
Como o módulo que você esta utilizando é diferente do deste tutorial, você deve utilizar um I2C Scanner para encontrar o endereço do seu módulo.