// audioguard.ino - BitDogLab / RP2040 Wokwi
// Potenciômetro GP28 → ADC → OLED + MQTT
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// ── Display ──────────────────────────────
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ── ADC (Microfone simulado) ──────────────
#define MIC_PIN 28
#define SAMPLE_INTERVAL_MS 1
#define BUFFER_SIZE 50
int sampleBuffer[BUFFER_SIZE];
int bufferIdx = 0;
unsigned long totalSamples = 0;
unsigned long lastSample = 0;
// ── WiFi ─────────────────────────────────
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// ── MQTT (HiveMQ público - sem TLS) ──────
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char* mqtt_topic = "audioguard/samples";
const char* mqtt_status = "audioguard/status";
const char* clientId = "bitdoglab-001";
WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);
// ── Estado ───────────────────────────────
unsigned long lastPublish = 0;
unsigned long packetsSent = 0;
const int PUBLISH_EVERY = 2000;
bool mqttConnected = false;
// ─────────────────────────────────────────
void drawDisplay(int raw, float vol, bool wifi, bool mqtt_ok) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// Título
display.setTextSize(1);
display.setCursor(0, 0);
display.print("AUDIOGUARD v1.0");
display.drawLine(0, 9, 127, 9, SSD1306_WHITE);
// ADC value
display.setCursor(0, 12);
display.print("ADC: ");
display.print(raw);
display.print(" / 4095");
// Volume bar
display.setCursor(0, 22);
display.print("Vol: ");
int barW = (int)(vol * 80);
display.drawRect(35, 22, 80, 8, SSD1306_WHITE);
display.fillRect(35, 22, barW, 8, SSD1306_WHITE);
display.setCursor(118, 22);
display.print((int)(vol*100));
// Amostras
display.setCursor(0, 33);
display.print("Amostras: ");
display.print(totalSamples);
// Status WiFi/MQTT
display.setCursor(0, 43);
display.print("WiFi:");
display.print(wifi ? " OK" : " --");
display.print(" MQTT:");
display.print(mqtt_ok ? " OK" : " --");
// Pacotes enviados
display.setCursor(0, 54);
display.print("Env: ");
display.print(packetsSent);
display.print(" pacotes");
display.display();
}
void connectWifi() {
Serial.print("Conectando WiFi");
WiFi.begin(ssid, password);
int tries = 0;
while (WiFi.status() != WL_CONNECTED && tries < 20) {
delay(500);
Serial.print(".");
tries++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi OK: " + WiFi.localIP().toString());
}
}
void connectMQTT() {
mqtt.setServer(mqtt_server, mqtt_port);
int attempts = 0;
while (!mqtt.connected() && attempts < 3) {
Serial.print("MQTT conectando...");
if (mqtt.connect(clientId)) {
Serial.println("OK");
mqttConnected = true;
mqtt.publish(mqtt_status, "{\"status\":\"online\",\"device\":\"bitdoglab\"}");
} else {
Serial.print("falhou rc=");
Serial.println(mqtt.state());
delay(2000);
attempts++;
}
}
}
void setup() {
Serial.begin(115200);
analogReadResolution(12);
Wire.begin();
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDR)) {
Serial.println("OLED falhou!");
while (true);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 10);
display.println("AudioGuard");
display.setTextSize(1);
display.setCursor(20, 40);
display.println("Iniciando...");
display.display();
delay(1500);
connectWifi();
connectMQTT();
Serial.println("Sistema pronto.");
}
void loop() {
// Reconecta MQTT se necessário
if (!mqtt.connected()) {
mqttConnected = false;
connectMQTT();
}
mqtt.loop();
unsigned long now = millis();
// Coleta amostra ADC
if (now - lastSample >= SAMPLE_INTERVAL_MS) {
lastSample = now;
int raw = analogRead(MIC_PIN);
sampleBuffer[bufferIdx % BUFFER_SIZE] = raw;
bufferIdx++;
totalSamples++;
float vol = raw / 4095.0f;
drawDisplay(raw, vol, WiFi.status() == WL_CONNECTED, mqttConnected);
}
// Publica pacote MQTT a cada 2 segundos
if (now - lastPublish >= PUBLISH_EVERY && mqttConnected) {
lastPublish = now;
// Calcula média e pico do buffer
long sum = 0;
int peak = 0;
int count = min((int)totalSamples, BUFFER_SIZE);
for (int i = 0; i < count; i++) {
sum += sampleBuffer[i];
if (sampleBuffer[i] > peak) peak = sampleBuffer[i];
}
float avg = (count > 0) ? (sum / (float)count) : 0;
// Monta JSON
StaticJsonDocument<256> doc;
doc["device"] = clientId;
doc["ts"] = now;
doc["avg_raw"] = (int)avg;
doc["peak_raw"] = peak;
doc["avg_v"] = avg / 4095.0f * 3.3f;
doc["total"] = totalSamples;
doc["vol_pct"] = (int)((peak / 4095.0f) * 100);
// Serializa e publica
char jsonBuf[256];
serializeJson(doc, jsonBuf);
if (mqtt.publish(mqtt_topic, jsonBuf)) {
packetsSent++;
Serial.print("[MQTT] Publicado #");
Serial.print(packetsSent);
Serial.print(" avg=");
Serial.println((int)avg);
}
}
}