// include libraries
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <TimeLib.h>
#include <ESP32Servo.h>
#include <Keypad.h>
#include <Wire.h>
#include <string>
#include <PubSubClient.h>
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 25200
#define UTC_OFFSET_DST 0
int count = 0;
long flagStart = 0;
const char* mqttServer = "test.mosquitto.org";
int port = 1883;
long lasDis = 0;
long distance = 0;
int potentiometer_val;
WiFiClient espClient;
PubSubClient client(espClient);
// global variables
bool isLoggedIn = false;
int isEnteredCorrectPin = -1; // -1: haven't enter pin yet.
bool isParking = false;
bool isTheftHappened = false;
bool isFireHappened = false;
bool isPay = false;
long validDistance = 0;
bool highSecurity = false;
int numberOfIncorrectPinInput = 0;
String password = "";
String price="";
long flag=0;
String targetPayment="fromDevice";
String requestPrice="sendPrice";
// keypad
const uint8_t ROWS = 4;
const uint8_t COLS = 4;
const char ENTER_KEY = '#';
int pwd_index_col = 1;
char keys[ROWS][COLS] =
{
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
uint8_t colPins[COLS] = { 16, 4, 2, 15 };
uint8_t rowPins[ROWS] = { 19, 18, 5, 17 };
// Devices
struct Devices
{
const short led = 25;
const short led_day_night = 3;
const short buzzer = 32;
const short ultrasonic_trig = 27;
const short ultrasonic_echo = 26;
const short button = 35;
const short flame_sensor = 36;
const short gas_sensor = 39;
const short potentiometer = 34;
const short photoresistor = 33;
const short pir_motion_sensor = 35;
const short servo_pin = 23;
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
LiquidCrystal_I2C LCD = LiquidCrystal_I2C(0x27, 20, 4);
Servo servo;
} devices;
// User
struct User
{
String personalPin = "";
} user;
// DISPLAY TIME
// DISPLAY MESSAGE
void displayMessage(String msg, int col, int row, int clearMode = 0)
{
if (clearMode)
{
turnOnLCD();
}
devices.LCD.backlight();
devices.LCD.setCursor(col, row);
devices.LCD.print(msg);
}
void callback(char* topic, byte* message, unsigned int length) {
String strMsg;
for (int i = 0; i < length; i++) {
strMsg += (char)message[i];
}
Serial.println(strMsg);
//Serial.println(highSecurity);
if (strstr((char*)strMsg.c_str(),"ID") && count == 0) {
for (int i = 3; i < strMsg.length(); i++)
{
password += strMsg[i];
}
count++;
}
if (strMsg == "open")
{
openBarrier();
char str[15];
Serial.println("Lua Gui tien hieu ve node-red");
sprintf(str, "%d", 0);
char fire[6] = "Fire:";
const char* fire_value = strcat(fire, str);
client.publish("20127329/test", fire_value);
char dis_title[10] = "Distance:";
char dis[15];
sprintf(dis, "%d", 0); // convert int to char *
const char* dis_value = strcat(dis_title, dis);
client.publish("20127329/test", dis_value);
distance = getDistance();
isPay = false;
isParking=false;
targetPayment="fromDevice";
requestPrice="sendPrice";
password="";
flag=0;
count=0;
}
if (strMsg == "Onhightsecurity")
{
highSecurity = true;
}
if (strMsg == "Offhightsecurity")
{
highSecurity = false;
}
if (strMsg == "check")
{
turnOnLCD();
inputPin();
targetPayment="fromApp";
requestPrice="noSendPrice";
validateUser();
}
if(strMsg=="continue")
{
payment();
targetPayment="fromDevice";
requestPrice="sendPrice";
}
if (strMsg == "done")
{
turnOnLCD();
goodBye();
isPay = false;
isParking=false;
targetPayment="fromDevice";
requestPrice="sendPrice";
password="";
flag=0;
count=0;
delay(5000);
}
if(strstr((char*)strMsg.c_str(),"VND"))
{
price=strMsg;
}
}
// ------- LCD HANDLE -------
// TURN OFF LCD
void turnOffLCD ()
{
devices.LCD.clear();
devices.LCD.noBacklight();
}
// TURN ON LCD
void turnOnLCD()
{
devices.LCD.clear();
devices.LCD.backlight();
devices.LCD.setCursor(0, 0);
}
void printLocalTime() {
//devices.LCD.backlight();
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
devices.LCD.setCursor(0, 1);
devices.LCD.println("Connection Error...");
return;
}
devices.LCD.setCursor(0, 0);
devices.LCD.println("TIME: ");
devices.LCD.setCursor(12, 0);
devices.LCD.println(&timeinfo, "%H:%M:%S");
devices.LCD.setCursor(0, 1);
devices.LCD.println("DATE: ");
devices.LCD.setCursor(10, 1);
devices.LCD.println(&timeinfo, "%d/%m/%Y");
}
// Create effect when connecting wifi
void spinner() {
static int8_t counter = 0;
const char* glyphs = "\xa1\xa5\xdb";
devices.LCD.setCursor(19, 0);
devices.LCD.print(glyphs[counter++]);
if (counter == strlen(glyphs)) {
counter = 0;
}
}
// ------- FLAME DETECT HANDLE -------
void flameDetect()
{
if (isParking)
{
int flame_val = analogRead(devices.flame_sensor);
int gas_val = analogRead(devices.gas_sensor);
potentiometer_val = analogRead(devices.potentiometer);
potentiometer_val = map(potentiometer_val, 0, 4095, 0, 100);
if (potentiometer_val > 50)
{
isFireHappened = true;
myTone(devices.buzzer);
digitalWrite(devices.led, HIGH);
displayMessage("...FLAME DETECTED...", 0, 0);
const char* caution_hot ="HOT";
client.publish("20127329/test", caution_hot);
delay(300);
}
else
{
isFireHappened = false;
myNoTone(devices.buzzer);
digitalWrite(devices.led, LOW);
turnOffLCD();
}
}
else
{
turnOffLCD();
}
}
// ------- DETECT DAY OR NIGHT -------
void dayNightDetect()
{
const float GAMMA = 0.7;
const float RL10 = 50;
int analogValue = analogRead(devices.photoresistor);
float voltage = analogValue / 4095. * 5;
float resistance = 2000 * voltage / (1 - voltage / 5);
float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
if (lux > 50) {
analogWrite(devices.led_day_night, 255);
} else {
analogWrite(devices.led_day_night, 0);
}
}
// ------- BUZZER HANDLE -------
// BUZZER set up before tone
void myTone(int pin)
{
float sinVal = (sin(180 * (3.1412 / 180)));
int toneVal = 2000 + (int(sinVal * 1000));
tone(pin, toneVal);
}
// BUZZER set up after tone
void myNoTone(int pin)
{
noTone(pin);
}
// ------- DISTANCE HANDLE -------
// get distance
long getDistance()
{
digitalWrite(devices.ultrasonic_trig, LOW);
delayMicroseconds(2);
digitalWrite(devices.ultrasonic_trig, HIGH);
delayMicroseconds(10);
digitalWrite(devices.ultrasonic_trig, LOW);
return pulseIn(devices.ultrasonic_echo, HIGH) * 0.034 / 2; // cm
}
void distanceDetect()
{
if (isParking && !validDistance)
{
distance = getDistance();
if (distance >= 150 && distance <= 250)
{
digitalWrite(devices.led, LOW);
myNoTone(devices.buzzer);
displayMessage("--------------------", 0, 0);
displayMessage("POSITION IS VALID...", 0, 1);
displayMessage("--------------------", 0, 2);
delay(2500);
turnOffLCD();
validDistance = distance;
}
else if (distance > 50 && distance < 150)
{
displayMessage("--------------------", 0, 0);
displayMessage("POSITION IS INVALID.", 0, 1);
displayMessage("--------------------", 0, 2);
myTone(devices.buzzer);
digitalWrite(devices.led, HIGH);
delay(500);
myNoTone(devices.buzzer);
digitalWrite(devices.led, LOW);
delay(500);
}
else // if distance <= 50 or distance > 250
{
displayMessage("--------------------", 0, 0);
displayMessage("POSITION IS INVALID.", 0, 1);
displayMessage("--------------------", 0, 2);
myTone(devices.buzzer);
digitalWrite(devices.led, HIGH);
delay(50 + distance);
myNoTone(devices.buzzer);
digitalWrite(devices.led, LOW);
delay(50 + distance);
}
}
if (isParking && validDistance && !isPay && abs(getDistance() - validDistance) >= 30)
{
myTone(devices.buzzer);
digitalWrite(devices.led, HIGH);
displayMessage("PRESS # TO DISABLE..", 0, 1, 1);
displayMessage("....THEFT HAPPEN....", 0, 0);
const char* caution ="THEFT";
client.publish("20127329/test", caution);
// disble flame dectected system
while (true)
{
if (devices.keypad.getKey() == '#')
{
myNoTone(devices.buzzer);
;
digitalWrite(devices.led, LOW);
turnOffLCD();
validDistance = getDistance();
break;
}
}
// code ...
}
}
// int flag=0;
// ------- INPUT PIN -------
void inputPin()
{
displayMessage("PRESS A TO ENTER PIN", 0, 0);
displayMessage("PRESS C TO CANCEL", 0, 2);
while (true) {
char key = devices.keypad.getKey();
if (key == 'A') break;
else if (key == 'C')
{
turnOffLCD();
isEnteredCorrectPin = -1;
numberOfIncorrectPinInput = 0;
return;
}
}
// Enter Pin
devices.LCD.clear();
displayMessage("ENTER YOUR PIN", 3, 0);
displayMessage("------------------", 1, 1);
displayMessage("------------------", 1, 3);
displayMessage("|", 0, 1);
displayMessage("|", 0, 2);
displayMessage("|", 0, 3);
displayMessage("|", 19, 1);
displayMessage("|", 19, 2);
displayMessage("|", 19, 3);
while (true)
{
if (highSecurity) break;
char key = devices.keypad.getKey();
if (key != NO_KEY)
{
displayMessage(String(key), pwd_index_col++, 2);
if (key != '#') user.personalPin += String(key);
else
{
pwd_index_col = 1;
break;
}
}
}
devices.LCD.clear();
devices.LCD.setCursor(3, 0);
devices.LCD.print("PROCESSING....");
devices.LCD.setCursor(0, 2);
devices.LCD.print("PLEASE WAIT A MINUTE");
delay(1500);
}
void payment()
{
displayMessage("PRICE: "+price, 2, 2);
displayMessage("PRESS # TO PAY", 3, 3);
while (true)
{
// show time
printLocalTime();
// show price
char key = devices.keypad.getKey();
if ( key == '#')
{
isPay = true;
// payment offline
displayMessage("Paid successfully...", 0, 0, 1);
openBarrier();
user.personalPin = "";
password="";
count=0;
numberOfIncorrectPinInput = 0;
break;
}
}
}
void goodBye()
{
displayMessage("GoodBye...", 0, 0, 1);
}
// ------- USER VALIDATION HANDLE -------
void validateUser()
{
if (user.personalPin == password && password!="" && !isParking) // if user enter correct pin and haven't parked yet.
{
displayMessage("VERIFIED COMPLETELY!", 0, 0, 1);
displayMessage("--------------------", 0, 1);
displayMessage("PARK THE CAR HERE...", 0, 2);
displayMessage("--------------------", 0, 3);
delay(2000);
turnOffLCD();
isEnteredCorrectPin = 1;
isParking = true;
user.personalPin = "";
numberOfIncorrectPinInput = 0;
}
else if (user.personalPin == password && isParking) // if user enter correct pin and have already parked the car.
{
if(requestPrice=="sendPrice"&&targetPayment=="fromDevice")
{
const char* getPrice = "getPrice";
client.publish("20127329/test", getPrice);
}else{
payment();
}
// payment online
// code right here...
}
else
{
if (user.personalPin == "") return;
displayMessage("PIN IS NOT CORRECT..", 0, 0, 1);
displayMessage("YOU HAVE " + String(2 - numberOfIncorrectPinInput) + " LEFT.....", 0, 1);
displayMessage("--------------------", 0, 2);
displayMessage("PRESS * TO TRY AGAIN", 0, 3);
numberOfIncorrectPinInput += 1;
if (numberOfIncorrectPinInput == 3)
{
myTone(devices.buzzer);
digitalWrite(devices.led, HIGH);
displayMessage("PRESS # TO DISABLE..", 0, 1, 1);
displayMessage("....THEFT HAPPEN....", 0, 0);
const char* caution1 ="THEFT";
client.publish("20127329/test", caution1);
while (true)
{
if (devices.keypad.getKey() == '#')
{
myNoTone(devices.buzzer);
digitalWrite(devices.led, LOW);
turnOffLCD();
numberOfIncorrectPinInput = 0;
break;
}
}
}
while (true) {
if (devices.keypad.getKey() == '*') break;
}
user.personalPin = ""; // reset personal pin
devices.LCD.clear();
isEnteredCorrectPin = 0;
}
}
// ------- BARRIER HANDLE -------
void openBarrier()
{
for (int deg = 180; deg >= 90; deg -= 1) {
devices.servo.write(deg);
delay(15);
}
delay(1000);
for (int deg = 90; deg <= 180; deg += 1) {
devices.servo.write(deg);
delay(15);
}
}
// ------- LCD HANDLE -------
void handleLCD ()
{
if (!highSecurity)
{
devices.LCD.clear();
char key = devices.keypad.getKey();
if (key == '*' || digitalRead(devices.pir_motion_sensor) == HIGH) // begin
{
turnOnLCD();
inputPin();
validateUser();
}
// case 1: Re-enter pin if user's pin is not correct.
if (!isEnteredCorrectPin && isEnteredCorrectPin != -1)
{
devices.LCD.backlight();
devices.LCD.setCursor(0, 0);
inputPin();
validateUser();
}
//while(true);
// Submit to server ...
}
else turnOffLCD();
}
// ------- CONNECT WIFT -------
void connectWifi()
{
displayMessage("Connecting to Wifi", 0, 0, 1);
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
spinner();
Serial.print(".");
}
displayMessage("Connected...", 0, 0, 1);
delay(1000);
turnOffLCD();
}
void sendMessage() {
if (flag==0||abs(potentiometer_val -map( analogRead(devices.potentiometer), 0, 4095, 0, 100))>=0.1)
{
char str[15];
sprintf(str, "%d", potentiometer_val);
char fire[6] = "Fire:";
const char* fire_value = strcat(fire, str);
client.publish("20127329/test", fire_value);
}
if (flag==0||abs(getDistance() - distance) >= 3) {
char dis_title[10] = "Distance:";
char dis[15];
sprintf(dis, "%d", getDistance()); // convert int to char *
const char* dis_value = strcat(dis_title, dis);
client.publish("20127329/test", dis_value);
distance = getDistance();
}
if (isPay) {
if(targetPayment=="fromDevice"){
const char* setData = "setdata";
client.publish("20127329/test", setData);
}
const char* target = "take";
client.publish("20127329/test", target);
isParking=false;
}
}
// ------- SETUP SYSTEM -------
void setup() {
devices.LCD.init();
// Serial.begin(9600); // Any baud rate should work
Serial.begin(115200);
// Init LCD
// Init flame sensor
pinMode(devices.flame_sensor, INPUT);
// Distance sensor
pinMode(devices.ultrasonic_trig, OUTPUT);
pinMode(devices.ultrasonic_echo, INPUT);
// Led
pinMode(devices.led, OUTPUT);
pinMode(devices.led_day_night, OUTPUT);
// Buzzer
pinMode(devices.buzzer, OUTPUT);
// gas sensor
pinMode(devices.gas_sensor, INPUT);
// poteniometer
pinMode(devices.potentiometer, INPUT);
// photoresistor
pinMode(devices.photoresistor, INPUT);
// motion sensor
pinMode(devices.pir_motion_sensor, INPUT);
// servo
devices.servo.attach(devices.servo_pin);
devices.servo.write(180);
// time config
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
// connect wifi
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
connectWifi();
client.setServer(mqttServer, port);
client.setCallback(callback);
}
void mqttReconnect() {
while (!client.connected()) {
Serial.println("Attemping MQTT connection...");
//***Change "123456789" by your student id***
if (client.connect("123456789")) {
Serial.println("connected");
//***Subscribe all topic you need***
client.subscribe("20127329/test");
}
else {
Serial.println("try again in 5 seconds");
delay(5000);
}
}
}
// put your main code here, to run repeatedly:
void loop() {
if (!client.connected()) {
mqttReconnect();
}
if(flag==0 && isParking)
{
sendMessage();
flag++;
}
if (isParking)
{
sendMessage();
}
handleLCD();
distanceDetect();
flameDetect();
dayNightDetect();
client.loop();
}