#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* thingspeak_api_key = "GVBNYNPF5HRBUOHC";
const char* thingspeak_url = "https://api.thingspeak.com/update";
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define DHTPIN 15
#define DHTTYPE DHT22
#define MQ2_PIN 36
#define PHOTO_PIN 39
#define SOIL_PIN 32
#define PIR_PIN 13
#define TRIG_PIN 5
#define ECHO_PIN 18
#define LED_LIGHT 23
#define LED_FAN 19
#define LED_HUMID 16
#define BUZZER_PIN 25
#define BUTTON_PIN 33
#define JOY_X_PIN 34
#define JOY_Y_PIN 35
#define JOY_SW_PIN 27
const float TEMP_FAN_ON = 30.0;
const float TEMP_ALARM = 60.0;
const int GAS_THRESHOLD = 2000;
const int DISTANCE_ALARM = 20;
const int LIGHT_THRESHOLD = 2000;
const int HUM_LOW = 40;
DHT dht(DHTPIN, DHTTYPE);
float temperature = 0;
float humidity = 0;
int gasLevel = 0;
int lightLevel = 0;
int soilValue = 0;
bool motionDetected = false;
float distanceCm = 400;
int joyX = 0;
int joyY = 0;
bool joyPressed = false;
bool buzzerManualOn = false;
bool lastBtn = HIGH;
unsigned long lastBtnEdge = 0;
unsigned long lastDisplayUpdate = 0;
unsigned long lastThingSpeakUpdate = 0;
float measureDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
float d = duration * 0.0343f / 2.0f;
if (d <= 0 || d > 400) return 400;
return d;
}
void connectToWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
unsigned long t0 = millis();
while (WiFi.status() != WL_CONNECTED && (millis() - t0) < 15000) {
delay(250);
}
}
void readSensors() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t)) temperature = t; else temperature = 0;
if (!isnan(h)) humidity = h; else humidity = 0;
gasLevel = analogRead(MQ2_PIN);
lightLevel = analogRead(PHOTO_PIN);
soilValue = analogRead(SOIL_PIN);
motionDetected = (digitalRead(PIR_PIN) == HIGH);
distanceCm = measureDistance();
joyX = analogRead(JOY_X_PIN);
joyY = analogRead(JOY_Y_PIN);
joyPressed = (digitalRead(JOY_SW_PIN) == LOW);
}
void handleButtonToggle() {
bool s = digitalRead(BUTTON_PIN);
unsigned long now = millis();
if (s != lastBtn) {
lastBtn = s;
lastBtnEdge = now;
}
if ((now - lastBtnEdge) > 30) {
static bool armed = true;
if (s == LOW && armed) {
buzzerManualOn = !buzzerManualOn;
armed = false;
}
if (s == HIGH) armed = true;
}
}
void setNormalOutputs() {
digitalWrite(LED_LIGHT, (lightLevel > LIGHT_THRESHOLD) ? HIGH : LOW);
digitalWrite(LED_HUMID, (humidity < HUM_LOW) ? HIGH : LOW);
digitalWrite(LED_FAN, (temperature > TEMP_FAN_ON) ? HIGH : LOW);
}
void alarmMode(const char* reason) {
bool s = (millis() / 200) % 2;
digitalWrite(LED_LIGHT, s);
digitalWrite(LED_FAN, !s);
digitalWrite(LED_HUMID, s);
tone(BUZZER_PIN, s ? 2000 : 1000);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(18, 8);
display.print("ALARM");
display.setTextSize(1);
display.setCursor(0, 40);
display.print(reason);
display.display();
}
void updateDisplay() {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.printf("T:%.1f H:%.0f%%", temperature, humidity);
display.setCursor(0, 12);
display.printf("Gas:%d Dist:%d", gasLevel, (int)distanceCm);
display.setCursor(0, 24);
display.printf("Light:%d Soil:%d", lightLevel, soilValue);
display.setCursor(0, 36);
display.printf("JX:%d JY:%d", joyX, joyY);
display.setCursor(0, 48);
display.printf("Buz:%d Btn:%d", buzzerManualOn ? 1 : 0, (digitalRead(BUTTON_PIN) == LOW) ? 1 : 0);
display.display();
}
void sendToThingSpeak() {
if (WiFi.status() != WL_CONNECTED) return;
String url = String(thingspeak_url) + "?api_key=" + thingspeak_api_key +
"&field1=" + String(temperature, 1) +
"&field2=" + String(humidity, 0) +
"&field3=" + String(gasLevel) +
"&field4=" + String(lightLevel) +
"&field5=" + String(motionDetected ? 1 : 0) +
"&field6=" + String(soilValue) +
"&field7=" + String(joyX) +
"&field8=" + String(joyY);
HTTPClient http;
http.begin(url);
int code = http.GET();
String body = http.getString();
http.end();
Serial.print("TS code=");
Serial.print(code);
Serial.print(" entry=");
Serial.println(body);
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(JOY_SW_PIN, INPUT_PULLUP);
pinMode(PIR_PIN, INPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(LED_LIGHT, OUTPUT);
pinMode(LED_FAN, OUTPUT);
pinMode(LED_HUMID, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LED_LIGHT, LOW);
digitalWrite(LED_FAN, LOW);
digitalWrite(LED_HUMID, LOW);
noTone(BUZZER_PIN);
analogReadResolution(12);
analogSetAttenuation(ADC_11db);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
dht.begin();
connectToWiFi();
}
void loop() {
handleButtonToggle();
readSensors();
bool alarm = false;
if (temperature > TEMP_ALARM) { alarm = true; alarmMode("OVERHEAT"); }
else if (gasLevel > GAS_THRESHOLD) { alarm = true; alarmMode("GAS"); }
else if (distanceCm < DISTANCE_ALARM) { alarm = true; alarmMode("DIST"); }
if (!alarm) {
setNormalOutputs();
if (buzzerManualOn) tone(BUZZER_PIN, 2000);
else noTone(BUZZER_PIN);
if (millis() - lastDisplayUpdate >= 250) {
updateDisplay();
lastDisplayUpdate = millis();
}
}
if (millis() - lastThingSpeakUpdate >= 16000) {
sendToThingSpeak();
lastThingSpeakUpdate = millis();
}
delay(30);
}