#include <LiquidCrystal.h>
#include <ESP32Servo.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#define ECHO_PIN_OUT 33
#define TRIG_PIN_OUT 25
#define ECHO_PIN_IN 12
#define TRIG_PIN_IN 32
#define DISTANCE 3
#define LED_PIN 27
#define LED_OPEN_PIN 26
#define SERVO_PIN 14
#define BUTTON_PIN 23
#define SPEAKER_PIN 17
// Thông tin kết nối WiFi
const char* name = "Wokwi-GUEST";
const char* password = "";
// Các link api sd
String getStoreStateUrl = "https://btl-iot.onrender.com/get/store_state";
String setStoreOpenUrl = "https://btl-iot.onrender.com/send/store_open";
String setStoreCloseUrl = "https://btl-iot.onrender.com/send/store_close";
String setCustomerInStoreUrl = "https://btl-iot.onrender.com/send/customer_in_store";
String addStoreInfoUrl = "https://btl-iot.onrender.com/send/shop_info";
String setHasThiefUrl = "https://btl-iot.onrender.com/update_theft";
WiFiClient client;
LiquidCrystal lcd(21, 22, 15, 5, 18, 19);
Servo servo;
int count_customer_in_store = 0;
int count_customer_in = 0;
int count_customer_out = 0;
bool isIn = false;
bool isOut = false;
bool isCloseStore = false;
int isSwitchOn = HIGH;
bool isNeedUpdateCloseStore = true;
bool isCloseByButton = false;
bool hasThief = false;
bool checkSentThiefNotification = false;
int timeSend = 0;
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN_OUT, OUTPUT);
pinMode(ECHO_PIN_OUT, INPUT);
pinMode(TRIG_PIN_IN, OUTPUT);
pinMode(ECHO_PIN_IN, INPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(LED_OPEN_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT);
lcd.begin(16, 2);
// Kết nối với Wi-Fi
WiFi.begin(name, password);
}
void loop() {
getStoreState();
storeIsClosed();
if (isCloseStore) {
checkThief();
closeStore();
delay(1000);
return;
}
// Cửa hàng mở cửa tắt thông báo trộm
hasThief = false;
sendThiefNotification();
checkSentThiefNotification = false;
openStore();
isNeedUpdateCloseStore = true;
float distanceIn = readDistanceIn();
float distanceOut = readDistanceOut();
Serial.print("distance in: ");
Serial.println(distanceIn);
in(distanceIn);
out(distanceOut);
Serial.print("count_customer_in_store: ");
Serial.println(count_customer_in_store);
controlLed();
showLCD();
if (checkWifiConnected() && timeSend >= 15) {
sendData();
}
Serial.println("------------------------------------------------");
timeSend++;
delay(1000);
}
void closeStore() {
// digitalWrite(LED_PIN, LOW);
digitalWrite(LED_OPEN_PIN, LOW);
if (isNeedUpdateCloseStore == true) {
isNeedUpdateCloseStore = false;
}
Serial.print("count_customer_in_store: ");
Serial.println(count_customer_in_store);
Serial.print("hasThief: ");
Serial.println(hasThief);
// Kiểm tra có trộm hay không
if (hasThief) {
if (!checkSentThiefNotification) {
sendThiefNotification();
checkSentThiefNotification = true;
}
for (int i=0; i< 5; i++) {
// Báo động
tone(SPEAKER_PIN, 440); // Nốt La (A)
delay(500);
noTone(SPEAKER_PIN);
delay(500);
}
}
closeDoor();
showLCD();
}
void openStore() {
isCloseStore = false;
digitalWrite(LED_OPEN_PIN, HIGH);
}
void storeIsClosed() {
int isClose = digitalRead(BUTTON_PIN); // Đọc trạng thái từ nút bấm
if (isClose == HIGH) { // Nhấn nút -> cửa hàng đóng
Serial.println("Store is closed 1");
isCloseStore = true;
isCloseByButton = true;
sendStoreState(setStoreCloseUrl);
return;
}
if (isSwitchOn == LOW && isClose == LOW && isCloseByButton == true) { // công tắc bật -> cửa hàng đóng
Serial.println("Store is opened 1");
isCloseStore = false;
isCloseByButton = false;
sendStoreState(setStoreOpenUrl);
return;
}
if (isSwitchOn == LOW && isClose == LOW && isCloseStore == false) { // nút trên server đóng -> cửa hàng đóng
Serial.println("Store is closed 2");
isCloseStore = true;
return;
}
if (isSwitchOn == HIGH && isClose == LOW) {
Serial.println("Store is opened 2");
isCloseStore = false;
return;
}
}
// -----------------------Các hàm gọi API--------------------------------
void getStoreState() {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin(getStoreStateUrl); // Kết nối tới Flask server
int httpResponseCode = http.GET(); // Gửi yêu cầu GET
String response = http.getString();
Serial.print("Server response: ");
Serial.println(response);
// Sử dụng ArduinoJson để phân tích chuỗi JSON
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, response);
// Kiểm tra xem có lỗi khi phân tích JSON không
if (error) {
Serial.print("Failed to parse JSON: ");
Serial.println(error.c_str());
} else {
// Lấy giá trị "is_close" từ JSON
String isClose = doc["is_close"];
if (isClose == "true") {
isSwitchOn = LOW;
isCloseStore = true;
closeStore();
Serial.println(" Cửa hàng dừng hoạt động: Switch OFF");
} else {
isSwitchOn = HIGH;
isCloseStore = false;
openStore();
Serial.println(" Cửa hàng đang hoạt động: Switch ON");
}
}
http.end(); // Kết thúc kết nối
}
// Gửi thông báo có trộm trong cửa hàng
void sendThiefNotification() {
String postDataInfo = "hasTheft=0";
if (hasThief) {
postDataInfo = "hasTheft=1";
}
String postDataCustomerInStore = "customer_in_store=" + String(count_customer_in_store);
sendPostRequest(setCustomerInStoreUrl, postDataCustomerInStore);
sendPostRequest(setHasThiefUrl, postDataInfo);
if (hasThief) Serial.println("Gửi thông báo có trộm lên Server Flask thành công");
else Serial.println("Không có trộm");
}
// Hàm gửi dữ liệu lên server Flask
void sendData() {
String postDataInfo = "customers_entering=" + String(count_customer_in) + "&customers_exiting=" + String(count_customer_out);
sendPostRequest(addStoreInfoUrl, postDataInfo);
String postDataCustomerInStore = "customer_in_store=" + String(count_customer_in_store);
sendPostRequest(setCustomerInStoreUrl, postDataCustomerInStore);
Serial.println("Đẩy dữ liệu lên Server Flask thành công");
}
// Hàm gửi trạng thái cửa hàng tới server Flask
void sendStoreState(String url) {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin(url);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
} else {
Serial.print("Error on sending POST: ");
Serial.println(httpResponseCode);
}
http.end();
}
void sendPostRequest(String serverUrl, String postData) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
// Gửi yêu cầu POST
int httpCode = http.POST(postData);
Serial.print("POST Data: ");
Serial.println(postData);
// Xử lý phản hồi từ server
if (httpCode > 0) {
String response = http.getString();
Serial.println("Response: " + response);
timeSend = 0;
count_customer_in = 0;
count_customer_out = 0;
} else {
Serial.print(">>>> Error on sending POST request: ");
Serial.println(httpCode);
}
http.end(); // Kết thúc kết nối
} else {
Serial.println("WiFi not connected");
}
}
// -----------------------Kiểm tra mạng----------------------------------
bool checkWifiConnected() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wifi not connected");
return false;
}
Serial.println("Wifi connected !");
Serial.println("Local IP: " + String(WiFi.localIP()));
WiFi.mode(WIFI_STA);
return true;
}
// ------------------------Sự kiện xảy ra tại cửa hàng--------------------------------------
void checkThief() {
float distanceIn = readDistanceIn();
float distanceOut = readDistanceOut();
Serial.print("distance in: ");
Serial.println(distanceIn);
in(distanceIn);
out(distanceOut);
if (count_customer_in_store > 0) hasThief = true;
else hasThief = false;
}
void openDoor() {
servo.attach(SERVO_PIN, 500, 2400);
servo.write(100);
}
void closeDoor() {
servo.attach(SERVO_PIN, 500, 2400);
servo.write(30);
}
void in(float distance) {
// Khi có người đi vào thì cửa mở,
// đợi người đi xa và ko có người nào đi ra thì cửa đóng
if (!isIn && distance <= DISTANCE) {
isIn = true;
count_customer_in_store++;
count_customer_in++;
if (!isCloseStore) openDoor();
} else if (isIn && distance >= DISTANCE) {
isIn = false;
if (!isOut) closeDoor();
}
}
void out(float distance) {
// Khi có người đi ra thì cửa mở,
// đợi người đi xa và ko có người nào đi vào thì cửa đóng
if (!isOut && distance <= DISTANCE && count_customer_in_store != 0) {
isOut = true;
count_customer_in_store--;
count_customer_out++;
if (!isCloseStore) openDoor();
} else if (isOut && distance >= DISTANCE) {
isOut = false;
if (!isIn) closeDoor();
}
}
float readDistanceOut() {
digitalWrite(TRIG_PIN_OUT, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN_OUT, HIGH);
delayMicroseconds(30);
digitalWrite(TRIG_PIN_OUT, LOW);
int duration = pulseIn(ECHO_PIN_OUT, HIGH);
// Serial.print("distance out: ");
// Serial.println(duration / 58);
return (float)duration / 58;
}
float readDistanceIn() {
digitalWrite(TRIG_PIN_IN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN_IN, HIGH);
delayMicroseconds(30);
digitalWrite(TRIG_PIN_IN, LOW);
int duration = pulseIn(ECHO_PIN_IN, HIGH);
// Serial.print("distance in: ");
// Serial.println(duration / 58);
return (float)duration / 58;
}
void showLCD() {
if (isCloseStore) {
lcd.clear();
lcd.setCursor(0, 0); // cột 0-16, hàng 0-1
lcd.print("DONG CUA");
return;
}
if (count_customer_in_store == 0) {
lcd.clear();
lcd.setCursor(0, 0); // cột 0-16, hàng 0-1
lcd.print("KHONG CO NGUOI");
lcd.setCursor(4, 1);
lcd.print("DEN TAT");
} else {
lcd.clear();
lcd.setCursor(0, 0); // cột 0-16, hàng 0-1
lcd.print("SO NGUOI:");
lcd.setCursor(10, 0);
lcd.print(count_customer_in_store);
lcd.setCursor(0, 1);
lcd.print("XINCHAOQUYKHACH");
}
}
// đèn bật khi cửa hàng mở và có người bên trong
void controlLed() {
if (count_customer_in_store <= 0) {
digitalWrite(LED_PIN, LOW);
} else {
Serial.print("count_customer_in_store: ");
Serial.println(count_customer_in_store);
digitalWrite(LED_PIN, HIGH);
}
}