/*
############################################################################
# Codigo Criado por: MarioParente
# Data: __/__/2023
# Detalhes do projeto: v0.1 - Hitórico de temperatura das ultima 24h
#
# # Atualizações:
# 20/08/23 - v0.1 - Introduzido suporte para diferentes tipos de sensores: DHT22 e BMP180
# Set/2024 - v0.2 - Implementado relógio para inicialização da hora
# - v0.2.1 - Realizada limpeza e otimização do código para melhor desempenho
# - v0.3 - Adicionado loop de tempo para controle contínuo
# - v0.3.1 - Melhorada a organização das funções e otimização do código
# - v0.3.2 - Desenvolvido termômetro dinâmico para visualização de temperatura
# - v0.3.3 - Mais otimizações no código para eficiência
# Out/2024 - v0.3.4 - Funções de exibição e menu reformuladas e otimizadas
############################################################################*/
// DHT22 Testado em __/__/____
// BMP180 Testado em 25/09/2024
// Clock Testado em 26/09/2024
#include <Adafruit_SSD1306.h> // Biblioteca para o display OLED
#include <DHTesp.h> // Biblioteca para o sensor DHT22
#include <BMP180I2C.h> // Biblioteca para o sensor BMP180
#include <RTClib.h> // Biblioteca para o RTC
#define I2C_ADDRESS 0x77 // Endereço I2C do sensor BMP180
//Variáveis globais
const int DHT_PIN = 15; // Pino do sensor DHT22
// Definição de variáveis de estado do sensor
int Sensor = 0;
// Definição de variáveis para temperatura e umidade
int T = 0, H = 0;
// Definição de variáveis para temperatura e umidade atuais, máximas e mínimas
int Atual_T = 0, Max_T = 0, Min_T = 0;
int Atual_H = 0, Max_H = 0, Min_H = 0;
int Menu = 0; // Controle do menu
// Ponto de tempo e coordenadas para gráfico
int T_Ponto = -1; // Ponto de tempo para gráfico
int Ponto_A = 0, Ponto_B = 0; // Coordenadas para o gráfico
// Instância dos sensores e do display
DHTesp dhtSensor;
TempAndHumidity data;
BMP180I2C bmp180(I2C_ADDRESS); // Instância do sensor BMP180
Adafruit_SSD1306 display(128, 64, &Wire); // Instância do display OLED
// Instância do RTC
RTC_DS1307 rtc;
//RTC_DS3231 rtc;
int falhasConsecutivas = 0; // Contador de falhas consecutivas na leitura do RTC
int Ano_ini = 0;
//
void ini_Sensor() {
// Auto detecção do sensor BMP180
if (!bmp180.begin()) {
display.setCursor(0, 30);
Serial.println(F("BMP180 Não Encontrado"));
display.print(F("BMP180 Nao Encontrado"));
} else {
display.setCursor(15, 30);
Serial.println(F("BMP180 Encontrado"));
display.print(F("BMP180 Encontrado"));
Sensor = 2; // Define o sensor BMP como ativo
}
if (Sensor == 0) { // Verifica se o BMP não foi encontrado
// Auto deteção do sensotr DHT22
// Obtém dados de temperatura e umidade do sensor DHT
TempAndHumidity data = dhtSensor.getTempAndHumidity();
if (String(data.temperature) == "nan") {
display.setCursor(5, 20);
Serial.println(F("DHT22 Não Encontrado"));
display.print(F("DHT22 Nao Encontrado"));
} else {
display.setCursor(20, 20);
Serial.println(F("DHT22 Encontrado"));
display.print(F("DHT22 Encontrado"));
Sensor = 1; // Define o sensor DHT como ativo
}
}
// Verifica a inicialização do RTC
if (!rtc.begin()) {
display.setCursor(10, 40);
display.print(F("RTC Não Encontrado"));
Serial.println("RTC Nao Encontrado");
} else {
display.setCursor(25, 40);
display.print(F("RTC Encontrado"));
Serial.println("RTC DS3231 Encontrado");
}
// Exibe a hora atual no Serial Monitor
DateTime now = rtc.now();
Ano_ini = now.year();
Serial.println(String(now.year()) + "-" + String(now.month()) + "-" + String(now.day()) + " " + String(now.hour()) + ":" + String(now.minute()));
delay(100);
}
void Sensor_DHT() {
// Obtém dados de temperatura e umidade do sensor DHT
TempAndHumidity data = dhtSensor.getTempAndHumidity();
// Converte os valores para inteiros
if (String(data.temperature) == "nan") {
Advertencia();
} else {
T = constrain(data.temperature, 0, 60);
H = constrain(data.humidity, 0, 99);
}
}
// Add adv
void Sensor_BMP() {
// Mede a temperatura com o BMP180
bmp180.measureTemperature();
delay(100); // Aguarda a medição ser concluída
// Verifica se a medição foi realizada com sucesso
if (bmp180.hasValue()) {
T = constrain(bmp180.getTemperature(), 0, 60);
}
// Como o BMP180 não mede umidade, define H como 0
H = 0;
}
void Tempo() {
// Obtém a hora e minutos do RTC
DateTime now = rtc.now();
// Verifica se o RTC está retornando uma data/hora válida
if (now.year() < Ano_ini) { // Se o ano lido for menor que o gravado na inicialização consideramos uma falha
falhasConsecutivas++;
if (falhasConsecutivas >= 5) {
//rtcValido = false;
Advertencia(); // Chama a função de advertência
}
} else {
falhasConsecutivas = 0;
// Atualiza o display apenas se o RTC estiver funcionando
int horaAtual = now.hour();
int minutoAtual = now.minute();
// Calcula o tempo total em blocos de 15 minutos
int MarcadorAtual = ((horaAtual * 60) + minutoAtual) / 15;
// Verifica se um novo ponto deve ser gerado
if (T_Ponto != MarcadorAtual) {
T_Ponto = MarcadorAtual;
Ponto(T_Ponto, T); // Chama a função para gerar o ponto
}
}
}
void Alteracao() {
Menu = (Menu + 1) % 3; // Alterna o Menu entre 0, 1 e 2
}
void Iniciando() {
// Inicializa o sensor
if (Sensor == 1) {
Sensor_DHT();
} else if (Sensor == 2) {
Sensor_BMP();
}
// Define valores iniciais de temperatura e umidade
Atual_T = Max_T = Min_T = T;
Atual_H = Max_H = Min_H = H;
// Obtém a hora e minutos do RTC
DateTime now = rtc.now();
int totalMinutos = now.hour() * 60 + now.minute(); // Cálculo total de minutos
// Calcula Ponto_A e Ponto_B
Ponto_A = (totalMinutos / 15) + 29; // Ponto_A ajustado
Ponto_B = map(Atual_T, 60, 0, 15, 51); // Mapeia Atual_T para Ponto_B
}
void ExibirDados(int tipo, int x, int n) {
display.fillRect(33, 0, 80, 8, BLACK);
//display.drawRect(33, 0, 80, 8, 1);
switch (tipo) {
case 0: // Exibe valores atuais
display.setCursor(33, 0);
display.print("Atual:" + String(x) + "C " + String(n) + "%");
break;
case 1: // Exibe valores máximos
Max_T = max(Max_T, x); // Atualiza Max_T se x for maior
Max_H = max(Max_H, n); // Atualiza Max_H se n for maior
display.setCursor(33, 0);
display.print("Max :" + String(Max_T) + "C " + String(Max_H) + "%");
break;
case 2: // Exibe valores mínimos
Min_T = min(Min_T, x); // Atualiza Min_T se x for menor
Min_H = min(Min_H, n); // Atualiza Min_H se n for menor
display.setCursor(33, 0);
display.print("Min :" + String(Min_T) + "C " + String(Min_H) + "%");
break;
}
}
void Grafico() {
display.drawLine(27, 53, 126, 53, 1); // linha Horizontal
display.drawLine(27, 13, 27, 53, 1); // linha Vertical
// Pontos linha horizontal
for (int i = 0; i <= 4; i++) {
display.drawPixel(29 + i * 24, 54, 1);
display.drawPixel(29 + i * 24, 55, 1);
}
// Pontos linha Vertical
for (int i = 0; i <= 4; i++) {
display.drawPixel(25, 15 + i * 9, 1);
display.drawPixel(26, 15 + i * 9, 1);
}
}
void Texto_grafico() {
// Texto horizontal hora
const char* horas[] = {"0", "6", "12", "18"};
int posX_horas[] = {27, 51, 72, 96};
for (int i = 0; i < 4; i++) {
display.setCursor(posX_horas[i], 57);
display.print(horas[i]);
}
// Texto vertical temperatura
const char* temperaturas[] = {"60", "45", "30", "15", " 0"};
int posY_temperaturas[] = {12, 21, 30, 39, 48};
for (int i = 0; i < 5; i++) {
display.setCursor(13, posY_temperaturas[i]);
display.print(temperaturas[i]);
}
// Legenda
display.setCursor(0, 0);
display.print("Temp");
display.setCursor(0, 57);
display.print("Hora");
}
void criarTermometro() {
// Marcação
display.drawLine(9, 15, 10, 15, WHITE); // Marcação na altura 14
display.drawLine(9, 24, 10, 24, WHITE); // Marcação na altura 23
display.drawLine(9, 33, 10, 33, WHITE); // Marcação na altura 32
display.drawLine(9, 42, 10, 42, WHITE); // Marcação na altura 41
display.drawPixel(10, 51, WHITE); // Marcação na altura 50
// Termômetro
display.drawPixel(5, 13, WHITE); // Topo do tubo
display.drawPixel(4, 14, WHITE); // Canto superior esquerdo
display.drawPixel(6, 14, WHITE); // Canto superior direito
display.drawLine(3, 15, 3, 54, WHITE); // Linha esquerda do tubo
display.drawLine(7, 15, 7, 54, WHITE); // Linha direita do tubo
display.drawLine(4, 49, 6, 49, WHITE); // Divisão entre tubo e bulbo
display.drawLine(2, 51, 2, 53, WHITE); // Linha esquerda do bulbo
display.drawLine(8, 51, 8, 53, WHITE); // Linha direita do bulbo
display.drawLine(4, 55, 6, 55, WHITE); // Base do bulbo
display.drawRect(3, 51, 5, 3, BLACK); // Espaço no meio do bulbo
display.drawPixel(5, 49, BLACK); // Espaço no meio
display.fillCircle(5, 52, 1, WHITE); // Bulbo
}
void Ponto(int x, int y) {
// Ajuste para o eixo x
x += 29;
// Limita o valor de y entre 0 e 60
y = constrain(y, 0, 60);
// Mapeia o valor de y para as coordenadas da tela
y = map(y, 60, 0, 15, 51);
// Desenha uma linha a partir do último ponto até o ponto atual
if (Ponto_A == 124) { //Verifica se estamos no final do gráfico (23:45) para desenhar até 24:00 (x = 125)
display.drawLine(Ponto_A, Ponto_B, 125, y, 1); // Desenha até 24:00
// Reinicia o gráfico no novo dia
Ponto_A = 29;
Ponto_B = y;
display.drawLine(Ponto_A, Ponto_B, Ponto_A, Ponto_B, 1); // Desenha também o novo 00:00
} else {
// Desenha o ponto normalmente
display.drawLine(Ponto_A, Ponto_B, x, y, 1);
// Atualiza Ponto_A e Ponto_B para o próximo ponto
Ponto_A = x;
Ponto_B = y;
}
}
void Mercurio(int a){
a = constrain(a, 0, 60);
a = map(a, 0, 60, 51, 15);
a = constrain(a, 15, 47);
display.drawLine(5, 47, 5, 14, BLACK); // Apaga o antigo
display.drawLine(5, 47, 5, a, WHITE); // Desenha o novo nível do mercúrio
}
void Advertencia() {
// Desenhar linha vertical
display.drawLine(122, 3, 122, 6, WHITE); // Ponto inicial (118, 3) até (118, 6)
// Desenhar pixel
display.drawPixel(122, 8, WHITE); // Pixel em (118, 8)
// Desenhar triângulo
display.drawTriangle(122, 0, 117, 9, 127, 9, WHITE); // Vértices (118, 0), (113, 9), (123, 9)
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(115200);
Serial.println("### Iniciando ###");
// Inicializa o display
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
// Configura o sensor DHT
dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
// Ajusta o contraste do display
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(25); // Define o nível de brilho para 10%
// Exibe a mensagem inicial
display.setTextColor(WHITE, BLACK);
display.setTextSize(1);
display.setCursor(20, 0);
display.print(F("Auto-Dedetecao"));
// Inicializa os sensores e outros componentes
ini_Sensor();
display.display();
// Pausa para a visualização da mensagem
delay(2000);
display.clearDisplay();
// Chama funções para configurar o gráfico e iniciar a exibição
Texto_grafico();
Grafico();
criarTermometro();
Iniciando();
display.display();
}
void loop() {
analogWrite(LED_BUILTIN, Menu == 0 ? 0 : 250);
// Seleção do sensor e obtenção dos dados
if (Sensor == 1) {
Sensor_DHT(); // Lê os dados do sensor DHT
} else if (Sensor == 2) {
Sensor_BMP(); // Lê os dados do sensor BMP
}
// Exibe as informações no display de acordo com o menu atual
ExibirDados(Menu, T, H);
Tempo();
Alteracao();
Mercurio(T);
display.display();
delay(1000);
}