#define BLYNK_TEMPLATE_ID "TMPL5MW5sXNMZ"
#define BLYNK_TEMPLATE_NAME "Smart Food Freshness and Kitchen Safety Monitoring"
#define BLYNK_AUTH_TOKEN "1mgKQi7Qo7dBnyDv2M24125_zp_ofqAd"
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <WebServer.h>
#include <DHT.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
const char* ssid = "Wokwi-GUEST";
const char* password = "";
WebServer server(80);
BlynkTimer timer;
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 4
#define TFT_MOSI 11
#define TFT_SCK 12
#define TFT_MISO 13
Adafruit_ILI9341 tft = Adafruit_ILI9341(
TFT_CS,
TFT_DC,
TFT_RST
);
#define DHTPIN 14
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#define GAS_PIN 1
#define TRIG_PIN 6
#define ECHO_PIN 7
#define PIR_PIN 15
#define LDR_PIN 2
#define RED_PIN 16
#define GREEN_PIN 17
#define BLUE_PIN 18
#define BUZZER_PIN 5
float temperature = 0;
float humidity = 0;
int gasLevel = 0;
int lightLevel = 0;
float distanceCM = 0;
int motionDetected = 0;
String aiPrediction = "FRESH";
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(PIR_PIN, INPUT_PULLDOWN);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
SPI.begin(TFT_SCK, TFT_MISO, TFT_MOSI);
tft.begin();
tft.setRotation(0);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(3);
tft.setCursor(20, 20);
tft.println("EdgeFresh AI");
delay(2000);
WiFi.begin(ssid, password);
Blynk.begin(
BLYNK_AUTH_TOKEN,
ssid,
password
);
Serial.print("Connecting WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi Connected");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.begin();
timer.setInterval(2000L, sendToBlynk);
}
void loop() {
Blynk.run();
timer.run();
readSensors();
runTinyML();
updateDisplay();
controlOutputs();
sendAlerts();
server.handleClient();
delay(2000);
}
void readSensors() {
temperature = dht.readTemperature();
humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
temperature = 25;
humidity = 50;
}
gasLevel = analogRead(GAS_PIN);
lightLevel = analogRead(LDR_PIN);
motionDetected = digitalRead(PIR_PIN);
Serial.print("RAW PIR: ");
Serial.println(motionDetected);
// Ultrasonic
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH);
distanceCM = duration * 0.034 / 2;
// SERIAL
Serial.println("====================");
Serial.print("Temperature: ");
Serial.println(temperature);
Serial.print("Humidity: ");
Serial.println(humidity);
Serial.print("Gas: ");
Serial.println(gasLevel);
Serial.print("Light: ");
Serial.println(lightLevel);
Serial.print("Distance: ");
Serial.println(distanceCM);
Serial.print("Motion: ");
Serial.println(motionDetected);
}
void runTinyML() {
int freshnessScore = 100;
freshnessScore -= map(gasLevel, 200, 4000, 0, 60);
freshnessScore -= map(temperature, 15, 50, 0, 25);
freshnessScore -= map(humidity, 30, 95, 0, 15);
freshnessScore = constrain(freshnessScore, 0, 100);
if (freshnessScore >= 75) {
aiPrediction = "FRESH";
}
else if (freshnessScore >= 50) {
aiPrediction = "WARNING";
}
else if (freshnessScore >= 25) {
aiPrediction = "SPOILING";
}
else {
aiPrediction = "DANGEROUS";
}
Serial.print("AI Prediction: ");
Serial.println(aiPrediction);
}
void updateDisplay() {
tft.fillScreen(ILI9341_BLACK);
// TITLE
tft.setTextSize(3);
tft.setTextColor(ILI9341_CYAN);
tft.setCursor(20, 10);
tft.println("EdgeFresh AI");
tft.drawLine(0, 40, 320, 40, ILI9341_WHITE);
// TEMP
tft.setTextSize(2);
tft.setTextColor(ILI9341_YELLOW);
tft.setCursor(10, 55);
tft.print("Temp: ");
tft.print(temperature);
tft.println(" C");
// HUMIDITY
tft.setTextColor(ILI9341_GREEN);
tft.setCursor(10, 85);
tft.print("Humidity: ");
tft.print(humidity);
tft.println(" %");
// GAS
tft.setTextColor(ILI9341_ORANGE);
tft.setCursor(10, 115);
tft.print("Gas: ");
tft.println(gasLevel);
// DISTANCE
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(10, 145);
tft.print("Distance: ");
tft.print(distanceCM);
tft.println(" cm");
// MOTION
tft.setCursor(10, 175);
if (motionDetected == 1) {
tft.setTextColor(ILI9341_RED);
tft.println("Motion: DETECTED");
}
else {
tft.setTextColor(ILI9341_GREEN);
tft.println("Motion: SAFE");
}
// AI STATUS
tft.drawLine(0, 210, 320, 210, ILI9341_WHITE);
tft.setTextSize(3);
tft.setCursor(20, 230);
if (aiPrediction == "FRESH") {
tft.setTextColor(ILI9341_GREEN);
}
else if (aiPrediction == "WARNING") {
tft.setTextColor(ILI9341_YELLOW);
}
else if (aiPrediction == "SPOILING") {
tft.setTextColor(ILI9341_ORANGE);
}
else {
tft.setTextColor(ILI9341_RED);
}
tft.println(aiPrediction);
}
void sendToBlynk() {
int gasPercent = map(gasLevel, 200, 4000, 0, 100);
gasPercent = constrain(gasPercent, 0, 100);
Blynk.virtualWrite(V0, temperature);
Blynk.virtualWrite(V1, humidity);
Blynk.virtualWrite(V2, gasPercent);
Blynk.virtualWrite(V3, distanceCM);
Blynk.virtualWrite(V4, motionDetected);
Blynk.virtualWrite(V5, aiPrediction);
}
void sendAlerts() {
if (aiPrediction == "DANGEROUS") {
Blynk.logEvent(
"dangerous_food",
"Dangerous food detected!"
);
}
if (gasLevel > 3000) {
Blynk.logEvent(
"gas_alert",
"High gas level detected!"
);
}
if (motionDetected == 1) {
Blynk.logEvent(
"motion_alert",
"Motion detected!"
);
}
}
void controlOutputs() {
if (aiPrediction == "FRESH") {
digitalWrite(GREEN_PIN, HIGH);
digitalWrite(RED_PIN, LOW);
digitalWrite(BLUE_PIN, LOW);
noTone(BUZZER_PIN);
}
else if (aiPrediction == "WARNING") {
digitalWrite(BLUE_PIN, HIGH);
digitalWrite(GREEN_PIN, LOW);
digitalWrite(RED_PIN, LOW);
tone(BUZZER_PIN, 1000);
}
else if (aiPrediction == "SPOILING") {
digitalWrite(RED_PIN, HIGH);
digitalWrite(GREEN_PIN, LOW);
digitalWrite(BLUE_PIN, LOW);
tone(BUZZER_PIN, 1500);
}
else {
digitalWrite(RED_PIN, HIGH);
digitalWrite(BLUE_PIN, HIGH);
digitalWrite(GREEN_PIN, LOW);
tone(BUZZER_PIN, 2000);
}
}
void handleRoot() {
String html = "";
html += "<html>";
html += "<head>";
html += "<meta http-equiv='refresh' content='3'>";
html += "<style>";
html += "body{background:#111;color:white;font-family:Arial;padding:20px;}";
html += ".card{background:#222;padding:15px;margin:10px;border-radius:12px;font-size:22px;}";
html += "</style>";
html += "</head>";
html += "<body>";
html += "<h1>EdgeFresh AI Dashboard</h1>";
html += "<div class='card'>Temperature: " + String(temperature) + " C</div>";
html += "<div class='card'>Humidity: " + String(humidity) + " %</div>";
html += "<div class='card'>Gas Level: " + String(gasLevel) + "</div>";
html += "<div class='card'>Light Level: " + String(lightLevel) + "</div>";
html += "<div class='card'>Distance: " + String(distanceCM) + " cm</div>";
html += "<div class='card'>Motion: " + String(motionDetected) + "</div>";
html += "<div class='card'><h2>AI Prediction: " + aiPrediction + "</h2></div>";
html += "</body>";
html += "</html>";
server.send(200, "text/html", html);
}