#include <WiFi.h>
#include <time.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <WebServer.h>
#define LDR_PIN 34
#define LED_PIN 19
// WiFi credentials - Use Wokwi wifi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Node-RED server configuration
// Replace with your Node-RED server IP address and port
const char* nodeRedServer = "http://127.0.0.1:1880/";
unsigned long lastSendTime = 0;
const unsigned long sendInterval = 5000; // Send data every 5 seconds
// Web server for receiving commands from Node-RED
WebServer server(80);
// NTP Server để lấy giờ
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 7 * 3600; // GMT+7
const int daylightOffset_sec = 0;
// Schedule
int scheduleonHour = 18;
int scheduleonMin = 0;
int scheduleoffHour = 5 ;
int scheduleoffMin = 30;
int minLight = 500;
int maxLight = 4000;
bool manualMode = true; // true = sensor, false = scheduled
// Global variables for current state
int currentHour, currentMinute, currentSecond;
int lightValue = 0;
int ledBrightness = 0;
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
ledcAttach(LED_PIN, 5000, 8);
//Wifi connection section
Serial.print("Đang kết nối Wifi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWifi đã kết nối!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// Setup web server routes for Node-RED communication
setupWebServer();
server.begin();
Serial.println("HTTP server started");
// NTP Configuration
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Serial.println("Lấy thông tin thời gian...");
// Wait for receive real time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Thất bại");
return;
}
Serial.println("Đã đồng bộ thời gian!");
printCurrentTime();
}
void loop() {
struct tm timeinfo;
// Handle web server requests
server.handleClient();
if (!getLocalTime(&timeinfo)) {
Serial.println("Thất bại");
delay(1000);
return;
}
currentHour = timeinfo.tm_hour;
currentMinute = timeinfo.tm_min;
currentSecond = timeinfo.tm_sec;
lightValue = analogRead(LDR_PIN);
// Schedule check
// In a day
if(currentHour >= scheduleonHour && currentHour <=scheduleoffHour){
if(currentMinute >= scheduleonMin && currentMinute <= scheduleoffMin){
manualMode = false;
}
else manualMode = true;
}
// through midnight
else if(currentHour <= scheduleoffHour){
manualMode = ((currentMinute <= scheduleoffMin) ? false : true);
}
// off schedule
else{
manualMode = true;
}
// LED brightness calculation
if (manualMode) {
// Manual mode - based on light sensor
if(lightValue <= minLight){
ledBrightness = 255;
}
else if(lightValue >= maxLight){
ledBrightness = 0;
}
else{
ledBrightness = map(lightValue, minLight, maxLight, 255, 0);
ledBrightness = constrain(ledBrightness, 0, 255);
}
}
else {
// Scheduled mode - full brightness
ledBrightness = 255;
}
// Apply brightness
ledcWrite(LED_PIN, ledBrightness);
// Print info
Serial.printf("%02d:%02d:%02d | Độ sáng: %d | Chế độ: %s | Phần trăm sáng: %d/255 (%d%%)\n",currentHour, currentMinute, currentSecond, lightValue, manualMode ? "Thủ công" : "Tự động", ledBrightness, (ledBrightness * 100) / 255);
// Send data to Node-RED every 5 seconds
if (millis() - lastSendTime >= sendInterval) {
sendDataToNodeRed();
lastSendTime = millis();
}
delay(1000);
}
void setupWebServer() {
// Handle CORS preflight requests
server.on("/control", HTTP_OPTIONS, []() {
server.sendHeader("Access-Control-Allow-Origin", "*");
server.sendHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "Content-Type");
server.send(200);
});
// Endpoint to receive control commands from Node-RED
server.on("/control", HTTP_POST, []() {
server.sendHeader("Access-Control-Allow-Origin", "*");
if (server.hasArg("plain")) {
String body = server.arg("plain");
Serial.println("Received command: " + body);
// Parse JSON command
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, body);
if (!error) {
// Handle different commands
if (doc.containsKey("mode")) {
String mode = doc["mode"];
if (mode == "manual") {
manualMode = true;
Serial.println("Switched to manual mode");
} else if (mode == "auto") {
manualMode = false;
Serial.println("Switched to auto mode");
}
}
if (doc.containsKey("brightness")) {
int brightness = doc["brightness"];
brightness = constrain(brightness, 0, 255);
ledBrightness = brightness;
ledcWrite(LED_PIN, ledBrightness);
Serial.println("Manual brightness set to: " + String(brightness));
}
if (doc.containsKey("schedule")) {
JsonObject schedule = doc["schedule"];
if (schedule.containsKey("onHour")) scheduleonHour = schedule["onHour"];
if (schedule.containsKey("onMin")) scheduleonMin = schedule["onMin"];
if (schedule.containsKey("offHour")) scheduleoffHour = schedule["offHour"];
if (schedule.containsKey("offMin")) scheduleoffMin = schedule["offMin"];
Serial.println("Schedule updated");
}
server.send(200, "application/json", "{\"status\":\"success\"}");
} else {
server.send(400, "application/json", "{\"status\":\"error\",\"message\":\"Invalid JSON\"}");
}
} else {
server.send(400, "application/json", "{\"status\":\"error\",\"message\":\"No data received\"}");
}
});
// Endpoint to get current status
server.on("/status", HTTP_GET, []() {
server.sendHeader("Access-Control-Allow-Origin", "*");
StaticJsonDocument<300> doc;
doc["timestamp"] = millis();
doc["time"] = String(currentHour) + ":" + String(currentMinute) + ":" + String(currentSecond);
doc["lightValue"] = lightValue;
doc["ledBrightness"] = ledBrightness;
doc["mode"] = manualMode ? "manual" : "auto";
doc["schedule"]["onHour"] = scheduleonHour;
doc["schedule"]["onMin"] = scheduleonMin;
doc["schedule"]["offHour"] = scheduleoffHour;
doc["schedule"]["offMin"] = scheduleoffMin;
doc["minLight"] = minLight;
doc["maxLight"] = maxLight;
String jsonString;
serializeJson(doc, jsonString);
server.send(200, "application/json", jsonString);
});
}
void sendDataToNodeRed() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.setTimeout(5000);
// Send to the HTTP input node endpoint
String url = String(nodeRedServer) + "/sensor-data";
Serial.println("Connecting to: " + url);
http.begin(url);
http.addHeader("Content-Type", "application/json");
// Create JSON payload
StaticJsonDocument<400> doc;
doc["timestamp"] = millis();
doc["time"] = String(currentHour) + ":" + String(currentMinute) + ":" + String(currentSecond);
doc["lightValue"] = lightValue;
doc["ledBrightness"] = ledBrightness;
doc["brightnessPercent"] = (ledBrightness * 100) / 255;
doc["mode"] = manualMode ? "manual" : "auto";
doc["schedule"]["onHour"] = scheduleonHour;
doc["schedule"]["onMin"] = scheduleonMin;
doc["schedule"]["offHour"] = scheduleoffHour;
doc["schedule"]["offMin"] = scheduleoffMin;
doc["ip"] = WiFi.localIP().toString();
String jsonString;
serializeJson(doc, jsonString);
Serial.println("Sending to Node-RED: " + jsonString);
int httpResponseCode = http.POST(jsonString);
Serial.println("HTTP Response Code: " + String(httpResponseCode));
if (httpResponseCode > 0) {
String response = http.getString();
Serial.println("Response: " + response);
Serial.println("Data sent successfully!");
} else if (httpResponseCode == -1) {
Serial.println("Connection failed - Check Node-RED is running");
} else if (httpResponseCode == -11) {
Serial.println("Timeout - Node-RED not responding");
} else {
Serial.println("HTTP Error: " + String(httpResponseCode));
}
http.end();
} else {
Serial.println("WiFi disconnected");
}
}
void printCurrentTime() {
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
Serial.printf("Thời gian hiện tại: %02d:%02d:%02d\n", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
}