#define BLYNK_TEMPLATE_ID "TMPL6PQgN1c4W"
#define BLYNK_TEMPLATE_NAME "15289"
#define BLYNK_AUTH_TOKEN "exNS3EcFLNHyG3G0fZ7EgWEFBDNT_5-3"
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ===== WiFi =====
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
// ===== Pins (ตามการต่อจริง) =====
#define DHTPIN 4
#define DHTTYPE DHT22
#define TRIG_PIN 5
#define ECHO_PIN 18
#define RED_PIN 14
#define GREEN_PIN 27
#define BLUE_PIN 26
#define I2C_SDA 21
#define I2C_SCL 22
// ===== OLED =====
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// ===== Objects/State =====
DHT dht(DHTPIN, DHTTYPE);
BlynkTimer timer;
bool manualOverride = false; // V3: 1=บังคับแดงค้าง, 0=Auto
unsigned long lastBlink = 0, lastDht = 0;
bool blinkOn = false;
const unsigned long BLINK_MS = 200;
const unsigned long DHT_MS = 2500;
float tempC = NAN, humi = NAN, distCM = NAN;
// ---------- Helpers ----------
float readDistanceCM() {
digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
unsigned long us = pulseIn(ECHO_PIN, HIGH, 60000UL); // 60ms timeout
if (us == 0) return NAN;
return (us * 0.0343f) / 2.0f;
}
void setRGB(uint8_t r, uint8_t g, uint8_t b) {
// ถ้าเป็น Common Anode ให้ใช้ 255-ค่า
analogWrite(RED_PIN, r);
analogWrite(GREEN_PIN, g);
analogWrite(BLUE_PIN, b);
}
void showOnOLED(const char* modeTxt) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Temp: "); if (isnan(tempC)) display.println("--"); else { display.print(tempC,1); display.println(" C"); }
display.print("Humi: "); if (isnan(humi)) display.println("--"); else { display.print(humi,1); display.println(" %"); }
display.print("Dist: "); if (isnan(distCM))display.println("--"); else { display.print(distCM,1); display.println(" cm"); }
display.print("Mode: "); display.println(modeTxt);
display.setCursor(0, 54); // บรรทัดล่างของจอ 64px
display.println("Kanyakorn 15289");
display.display();
}
// ---------- Blynk ----------
BLYNK_WRITE(V3) { // Switch 0/1
manualOverride = (param.asInt() == 1);
}
BLYNK_CONNECTED() {
// บังคับให้เริ่มจาก OFF เพื่อกัน MANUAL ค้าง
manualOverride = false;
Blynk.virtualWrite(V3, 0);
Blynk.syncVirtual(V3);
}
// ---------- Main tick (100ms) ----------
void tick() {
unsigned long now = millis();
// DHT: อ่านไม่ถี่กว่า 2.5s
if (now - lastDht >= DHT_MS) {
lastDht = now;
float h = dht.readHumidity();
float t = dht.readTemperature();
if (!isnan(h)) { humi = h; Blynk.virtualWrite(V1, humi); }
if (!isnan(t)) { tempC = t; Blynk.virtualWrite(V0, tempC); }
}
// ระยะ (อ่านได้บ่อย)
float d = readDistanceCM();
if (!isnan(d)) { distCM = d; Blynk.virtualWrite(V2, distCM); }
// ควบคุมไฟ
const char* modeTxt = "AUTO";
if (manualOverride) {
setRGB(255,0,0); modeTxt = "MANUAL";
} else {
if (isnan(distCM)) {
setRGB(0,0,0);
} else if (distCM < 20) {
setRGB(255,0,0);
} else if (distCM <= 30) {
if (now - lastBlink >= BLINK_MS) { lastBlink = now; blinkOn = !blinkOn; }
setRGB(blinkOn ? 255 : 0, blinkOn ? 255 : 0, 0); // เหลืองกระพริบ
} else {
setRGB(0,0,255);
}
}
// แสดงผล + ดีบัก
showOnOLED(modeTxt);
Serial.printf("WiFi=%s Blynk=%s T=%.1f H=%.1f D=%.1f MODE=%s\n",
WiFi.isConnected()?"OK":"NO",
Blynk.connected()?"OK":"NO",
isnan(tempC)?-999:tempC,
isnan(humi)?-999:humi,
isnan(distCM)?-999:distCM,
modeTxt);
}
// ---------- Setup / Loop ----------
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
setRGB(0,0,0);
Wire.begin(I2C_SDA, I2C_SCL);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.display();
dht.begin();
Blynk.begin(BLYNK_AUTH_TOKEN, WIFI_SSID, WIFI_PASS);
timer.setInterval(100L, tick);
}
void loop() {
Blynk.run();
timer.run();
}
.