// Projekt: Michał Rutka
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <HTTPClient.h>
#include "secrets.h"
#define PIN_DHT 15
#define TYP_DHT DHT22
#define PIN_MQ2 34
#define PIN_LED 2
#define PIN_BUZZERA 4
#define SZER_OKNA 128
#define WYS_OKNA 64
#define ADR_OLED 0x3C
Adafruit_SSD1306 wyswietlacz(SZER_OKNA, WYS_OKNA, &Wire, -1);
WiFiClientSecure klientWiFi;
PubSubClient klientMqtt(klientWiFi);
DHT czujnikDHT(PIN_DHT, TYP_DHT);
bool alarmAktywny = false;
// --- Kalibracja (ADC vs rzeczywiste ppm z suwakiem) ---
const int CAL_N = 7;
const int adcCal[CAL_N] = { 843, 1019, 1619, 2603, 3325, 3686, 3762 };
const float ppmCal[CAL_N] = { 0.1, 0.2, 1.0, 10.0, 100.0, 575.0,1000.0 };
// Funkcja interpolująca liniowo między punktami kalibracji
float mapPPM(int adc) {
if (adc <= adcCal[0]) return ppmCal[0];
if (adc >= adcCal[CAL_N-1]) return ppmCal[CAL_N-1];
for (int i = 0; i < CAL_N-1; i++) {
int x0 = adcCal[i], x1 = adcCal[i+1];
float y0 = ppmCal[i], y1 = ppmCal[i+1];
if (adc >= x0 && adc <= x1) {
return y0 + (y1 - y0) * (float)(adc - x0) / (float)(x1 - x0);
}
}
return 0; // nie powinno się zdarzyć
}
void setup() {
Serial.begin(115200);
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_BUZZERA, OUTPUT);
czujnikDHT.begin();
Wire.begin(21, 22);
if (!wyswietlacz.begin(SSD1306_SWITCHCAPVCC, ADR_OLED)) {
Serial.println("Błąd inicjalizacji ekranu OLED");
while (1);
}
delay(2000);
wyswietlacz.clearDisplay();
wyswietlacz.setTextSize(1);
wyswietlacz.setTextColor(SSD1306_WHITE);
// Wi‑Fi i MQTT
Serial.print("Łączenie z Wi‑Fi");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(200);
Serial.print(".");
}
Serial.println(" połączono");
klientWiFi.setInsecure();
klientMqtt.setServer(MQTT_HOST, MQTT_PORT);
}
void polaczMQTT() {
while (!klientMqtt.connected()) {
Serial.print("Łączenie z brokerem MQTT...");
if (klientMqtt.connect("ESP32Client", MQTT_USER, MQTT_PASS)) {
Serial.println(" OK");
} else {
Serial.print(" niepowodzenie, kod=");
Serial.println(klientMqtt.state());
delay(2000);
}
}
}
void odczytajCzujniki(float &T, float &H, float &P) {
T = czujnikDHT.readTemperature();
H = czujnikDHT.readHumidity();
int adc = analogRead(PIN_MQ2); // 0–4095
float V = adc * (3.3 / 4095.0); // napięcie
P = mapPPM(adc); // interpolacja
Serial.printf("MQ-2: ADC=%d V=%.2fV ppm≈%.1f\n", adc, V, P);
}
void aktualizujDisplay(float T, float H, float P) {
wyswietlacz.clearDisplay();
wyswietlacz.setCursor(0, 0);
wyswietlacz.printf("Temp: %.1f C\n", T);
wyswietlacz.printf("Wilg: %.1f %%\n", H);
wyswietlacz.printf("Dym: %.1f ppm\n", P);
if (alarmAktywny) {
wyswietlacz.setTextColor(SSD1306_INVERSE);
wyswietlacz.setCursor(0, 52);
wyswietlacz.println("!!! ALARM !!!");
wyswietlacz.setTextColor(SSD1306_WHITE);
}
wyswietlacz.display();
}
void publikujMQTT(float T, float H, float P) {
char buf[64];
dtostrf(T,4,1,buf); klientMqtt.publish("iot/temperatura-michalrutka", buf);
dtostrf(H,4,1,buf); klientMqtt.publish("iot/wilgotnosc-michalrutka", buf);
dtostrf(P,4,1,buf); klientMqtt.publish("iot/dym-michalrutka", buf);
}
void wyslijWebhook(float T, float H, float P) {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
String url = String("https://") + WEBHOOK_HOST + WEBHOOK_PATH;
http.begin(url);
http.addHeader("Content-Type", "application/json");
String j = String("{\"temperatura\":") + T +
",\"wilgotnosc\":" + H +
",\"dym\":" + P +
",\"alarm\":true}";
int code = http.POST(j);
Serial.printf("Webhook HTTP status: %d\n", code);
http.end();
}
void sprawdzAlarm(float T, float H, float P) {
bool alarm = (T > 50.0 || P > 600.0);
if (alarm && !alarmAktywny) {
digitalWrite(PIN_LED, HIGH);
digitalWrite(PIN_BUZZERA, HIGH);
Serial.println("ALARM! Wysłanie powiadomienia...");
wyslijWebhook(T,H,P);
}
if (!alarm && alarmAktywny) {
Serial.println("Stan bezpieczny, wyłączam alarm");
digitalWrite(PIN_LED, LOW);
digitalWrite(PIN_BUZZERA, LOW);
}
alarmAktywny = alarm;
}
void loop() {
if (!klientMqtt.connected()) polaczMQTT();
klientMqtt.loop();
float temp, hum, ppm;
odczytajCzujniki(temp, hum, ppm);
Serial.printf("Odczyt → Temp=%.1fC Wilg=%.1f%% Dym=%.1f ppm\n",
temp, hum, ppm);
if (!isnan(temp) && !isnan(hum)) {
sprawdzAlarm(temp, hum, ppm);
publikujMQTT(temp, hum, ppm);
aktualizujDisplay(temp, hum, ppm);
}
delay(2000);
}