/* INCLUSÃO DAS BIBLIOTECAS */
//#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <math.h>
// ==== MODO DE OPERAÇÃO (descomentar) ====
// #define MODO_REAL // usa o HC-SR04 real
#define MODO_SIM_SENO // simulação senoidal 0..400 cm
// #define MODO_SIM_RAMPA // simulação em rampa 0..400 cm
// ======================================
/* WIFI (Wokwi) */
const char* ssid = "Wokwi-GUEST"; //wifi do wokwi
const char* password = ""; // sem senha
/* ThingSpeak */
const char* tsServer = "http://api.thingspeak.com/update"; // endereço do servidor do ThingSpeak, recebe dados
String apiKey = "YN5G6T1J0D3IE602"; // Write API Key
/* DEFINIÇÃO DOS OBJETOS */
LiquidCrystal_I2C lcd(0x27, 16, 2); // Endereço I2C 0x27, LCD 16 colunas x 2 linhas
#define LED_PIN 5
#define LED_COUNT 1 // Só 1 LED (NeoPixel)
/* DEFINIÇÃO DOS PINOS DOS SENSOR ULTRASSÔNICO */
#define TRIG_PIN 12
#define ECHO_PIN 14
/* DEFINIÇÃO DOS PINOS DO BUZZER */
#define BUZZER_PIN 27
//#define BUZZER_CHANNEL 0 // Canal PWM p/ o buzzer
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
byte bar0[8] = {0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000,0b00000}; // vazio
byte bar1[8] = {0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000,0b10000};
byte bar2[8] = {0b11000,0b11000,0b11000,0b11000,0b11000,0b11000,0b11000,0b11000};
byte bar3[8] = {0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100,0b11100};
byte bar4[8] = {0b11110,0b11110,0b11110,0b11110,0b11110,0b11110,0b11110,0b11110};
byte bar5[8] = {0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111}; // cheio
/* TIMER p/ envio ao ThingSpeak */
unsigned long lastSend = 0;
const unsigned long SEND_INTERVAL_MS = 20000; // 20 s (>= 15 s no plano free)
void setup() {
// Inicia o LED endereçável e o deixa apagado (strip.show() com tudo zerado).
strip.begin();
strip.show();
strip.setBrightness(100);
// Configura o sensor de distância (TRIG como saída, ECHO como entrada).
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// Prepara o buzzer
pinMode(BUZZER_PIN, OUTPUT);
//ledcAttachPin(BUZZER_PIN, BUZZER_CHANNEL);
// Inicializa o LCD e mostra uma mensagem temporária de "Distance" por 3 segundos.
lcd.init();
lcd.createChar(0, bar0);
lcd.createChar(1, bar1);
lcd.createChar(2, bar2);
lcd.createChar(3, bar3);
lcd.createChar(4, bar4);
lcd.createChar(5, bar5);
lcd.backlight();
lcd.print("--> Distance <--");
delay(3000);
lcd.clear();
// Wi-Fi
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("Conectando ao WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi conectado!");
}
//------------------------- FUNÇAO PARA PREENCHER A TIRA COM UMA COR -------------------//
void colorWipe(uint32_t color, int wait) {
//Essa função pinta o(s) LED(s) do NeoPixel com a cor que você passar (vermelho, verde, azul).
for(int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, color);
strip.show();
delay(wait);
}
}
//----------------------------------------------------------------------------------------//
//------------------------- FUNÇÃO PARA DESENHAR A BARRA ---------------------------------//
void drawLevelBar(float distancia) {
int maxDist = 400; // ajuste para sua aplicação
int blocks = 16; // largura da barra (em caracteres LCD)
// Converte distância em porcentagem (inverso: menor distância = cheio)
int nivel = constrain((maxDist - distancia) * 100 / maxDist, 0, 100);
int fullBlocks = map(nivel, 0, 100, 0, 16); // até 20 blocos no LCD 20x4
//int fullBlocks = nivel / 10; // blocos completos
int partial = (nivel % 10) / 2; // parcial (0 a 4)
lcd.setCursor(0, 1);
for (int i = 0; i < blocks; i++){
if (i < fullBlocks) {
lcd.write(5); // bloco cheio
}
else if (i == fullBlocks && partial > 0) {
lcd.write(partial); // bloco parcial
}
else {
lcd.write(0); // bloco vazio
}
}
}
//----------------------------------------------------------------------------------------//
//------------------------- LOOP PRINCIPAL -----------------------------------------------//
void loop() {
// put your main code here, to run repeatedly:
//delay(10); // this speeds up the simulation
//long distancia = readDistanceCM(); // leitura do sensor
float distancia = 0; // inicia variável
#if defined(MODO_REAL)
// leitura REAL do HC-SR04
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000UL); // timeout 30 ms
distancia = (duration == 0) ? 400.0 : duration / 58.0; // default 400 se não mede
#elif defined(MODO_SIM_SENO)
// simulação SENOIDAL
static float x = 0;
x += 0.10;
distancia = (sin(x) + 1.0) * 200.0; // 0..400 cm
#elif defined(MODO_SIM_RAMPA)
// simulação RAMPA
static float d = 0;
d += 5;
if (d > 400) d = 0;
distancia = d;
#endif
// sempre limitar à faixa 0–400
distancia = constrain(distancia, 0, 400);
// Mostra a distância em centímetros na primeira linha do display.
lcd.setCursor(0, 0);
lcd.print("Dist: ");
lcd.print(distancia);
lcd.print(" cm");
//De acordo com a distância, o sistema:
lcd.setCursor(0, 1);
if (distancia >= 300) {
// Nível crítico (vazio) - Vermelho
colorWipe(strip.Color(255, 0, 0), 0);
digitalWrite(BUZZER_PIN, HIGH);
//ledcWriteTone(BUZZER_CHANNEL, 1500); // agudo
drawLevelBar(distancia);
//lcd.print("Nivel: CRITICO ");
}
else if (distancia >= 150) {
// Nível intermediário - Azul
colorWipe(strip.Color(0, 0, 255), 0);
digitalWrite(BUZZER_PIN, LOW);
drawLevelBar(distancia);
//lcd.print("Nivel: MEDIO ");
}
else{
// Nível cheio - Verde
colorWipe(strip.Color( 0,255, 0), 0);
digitalWrite(BUZZER_PIN, LOW);
drawLevelBar(distancia);
//lcd.print("Nivel: CHEIO ");
}
// -------- Envio ao ThingSpeak a cada 20s --------
if (WiFi.status() == WL_CONNECTED && (millis() - lastSend >= SEND_INTERVAL_MS)) {
lastSend = millis();
// Estado 0=Cheio, 1=Intermediário, 2=Crítico
int estado = (distancia >= 300) ? 2 : (distancia >= 150 ? 1 : 0);
// % de nível (0–100%)
int nivelPct = constrain(map((int)distancia, 0, 400, 100, 0), 0, 100);
HTTPClient http;
String url = String(tsServer) + "?api_key=" + apiKey +
"&field1=" + String(distancia, 1) +
"&field2=" + String(nivelPct) +
"&field3=" + String(estado);
http.begin(url);
int httpCode = http.GET();
if (httpCode > 0) {
Serial.println("ThingSpeak OK: " + String(httpCode));
} else {
Serial.println("Falha ThingSpeak");
}
http.end();
}
delay(1000);
}