#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <SPI.h>
#include <Keypad.h>
#include <FirebaseESP32.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <ArduinoJson.h>
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"
using namespace std;
/*-------KeyPad Init------*/
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] =
{
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}};
byte rowPins[ROWS] = {12, 14, 27, 26};
byte colPins[COLS] = {25, 33, 32, 35};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
/*-------Dispay Init------*/
#define CS 5
#define RST 15
#define DC 4
#define MOSI 23 // DIN
#define SCLK 18 // CLK
#define MISO 19 // BL
Adafruit_ILI9341 LCD = Adafruit_ILI9341(CS, DC);
char ID_Value[10];
uint8_t b_len = 9;
uint8_t p_len = 5;
// char PostID_Value [5];
uint8_t ValueIndex;
uint8_t PostIDIndex;
uint8_t state; // 0 - Start //1 - BioID //2 - PostCode //3 - voting
/*-------Firebase Init------*/
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""
#define API_KEY "AIzaSyAnIyBy4OkkpnzfaqwVfdFFsntPQZNqgoc"
#define DATABASE_URL "https://votersdatabase-default-rtdb.firebaseio.com/"
FirebaseJson json;
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
unsigned long sendDataPrevMillis = 0;
bool signupOK = false;
/*-----Init Push BUttons-----*/
const int buttonPins[] = {22, 21, 17, 16, 0, 2};
const int numButtons = sizeof(buttonPins) / sizeof(buttonPins[0]);
string defaultPath = "1CJZMmYwsDLgfE5_KTIlcwavROm_LYBryyCkcgagFdVc";
StaticJsonDocument<1024> FingerDatas;
StaticJsonDocument<1024> Candidates;
StaticJsonDocument<200> SelectedVoter;
string ElectID;
void InitFirebase()
{
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
Serial.printf("Firebase Client v%s\n\n", FIREBASE_CLIENT_VERSION);
config.api_key = API_KEY;
config.database_url = DATABASE_URL;
if (Firebase.signUp(&config, &auth, "", ""))
{
Serial.println("Firebase signup OK");
signupOK = true;
}
else
{
Serial.printf("%s\n", config.signer.signupError.message.c_str());
}
config.token_status_callback = tokenStatusCallback;
Firebase.begin(&config, &auth);
Firebase.reconnectNetwork(true);
}
// Start Display message
void initDisplay()
{
state = 0;
LCD.fillScreen(ILI9341_BLACK);
LCD.setTextColor(ILI9341_WHITE);
LCD.setTextSize(3);
LCD.setCursor(0, 0);
LCD.println("Welcome to General Election!!\n");
LCD.println("Please enter '#' to start..");
}
// Init Push Button pins and mode
void InitPushBtn()
{
for (int i = 0; i < numButtons; i++)
{
pinMode(buttonPins[i], INPUT_PULLUP);
}
}
void GetVotersData()
{
string path = defaultPath + "/Fingers";
if (Firebase.ready() && signupOK &&
(millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
if (Firebase.getString(fbdo, path.c_str()))
{
FingerDatas.clear();
DeserializationError error1 = deserializeJson(FingerDatas, fbdo.stringData());
if (error1)
{
Serial.print("Failed to parse Finger JSON: ");
Serial.println(error1.f_str());
}
for (JsonVariant value : FingerDatas.as<JsonArray>())
{
if (!value.isNull())
{
const char *BioID = value["BioID"];
const char *FingerID = value["FingerID"];
const char *FingerTemplate = value["FingerTemplate"];
const char *Name = value["Name"];
const char *PostID = value["PostID"];
Serial.print("BioID: ");
Serial.println(BioID);
Serial.print("FingerID: ");
Serial.println(FingerID);
Serial.print("FingerTemplate: ");
Serial.println(FingerTemplate);
Serial.print("Name: ");
Serial.println(Name);
Serial.print("PostID: ");
Serial.println(PostID);
Serial.println();
}
}
}
}
}
void GetCandidateData()
{
string path = defaultPath + "/Candidates";
if (Firebase.ready() && signupOK &&
(millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
if (Firebase.getString(fbdo, path.c_str()))
{
Candidates.clear();
DeserializationError error1 = deserializeJson(Candidates, fbdo.stringData());
if (error1)
{
Serial.print("Failed to parse Candidates JSON: ");
Serial.println(error1.f_str());
}
int index = 1;
for (JsonVariant value : Candidates.as<JsonArray>())
{
if (!value.isNull())
{
value["IndexID"] = index++;
const char *CandicateID = value["CandicateID"];
const char *CandidateName = value["CandidateName"];
const char *Election = value["Election"];
Serial.print("CandicateID: ");
Serial.println(CandicateID);
Serial.print("CandidateName: ");
Serial.println(CandidateName);
Serial.print("Election: ");
Serial.println(Election);
Serial.println();
}
}
}
}
}
bool isAlredyVoted()
{
string Path = defaultPath + "/Voting";
if (Firebase.ready() && signupOK &&
(millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
if (Firebase.getString(fbdo, Path.c_str()))
{
StaticJsonDocument<1024> Vote;
DeserializationError error1 = deserializeJson(Vote, fbdo.stringData());
if (error1)
{
Serial.print("Failed to parse Candidates JSON: ");
Serial.println(error1.f_str());
}
for (JsonVariant value : Vote.as<JsonArray>())
{
if (!value.isNull())
{
if (Vote["ElectID"] == ElectID && Vote["FingID"] == SelectedVoter["FingerID"])
{
return true;
}
}
}
}
}
return false;
}
int getVotersCount()
{
int count = 0;
string path = defaultPath + "/Voting";
if (Firebase.ready() && signupOK &&
(millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
if (Firebase.getString(fbdo, path.c_str()))
{
StaticJsonDocument<1024> Votes;
DeserializationError error1 = deserializeJson(Votes, fbdo.stringData());
if (error1)
{
Serial.print("Failed to parse JSON2: ");
Serial.println(error1.f_str());
}
for (JsonVariant value : Votes.as<JsonArray>())
{
if (!value.isNull())
{
count++;
}
}
return count;
}
}
return count;
}
void StoreVotes()
{
string Path = defaultPath + "/Voting/";
int voteCount = getVotersCount();
voteCount++;
if (Firebase.ready() && signupOK &&
(millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0))
{
sendDataPrevMillis = millis();
json.set("CandiID", "2");
json.set("ElectID", ElectID);
json.set("FingID", "E1");
json.set("ID", voteCount);
json.set("TimeStamp", millis() / 1000);
string vtCount = std::to_string(voteCount);
string NewPath = Path + vtCount;
if (Firebase.setJSON(fbdo, NewPath.c_str(), json))
{
Serial.println("Data sent to Firebase successfully");
}
else
{
Serial.print("Failed to send data to Firebase: ");
Serial.println(fbdo.errorReason());
}
}
}
bool isfull = false;
void nextChar(char key)
{
if ((state == 4 && ValueIndex < b_len) || (state == 5 && ValueIndex < p_len))
{
LCD.setTextColor(ILI9341_WHITE);
ID_Value[ValueIndex] = key;
LCD.setCursor((ValueIndex * 18), 100);
LCD.println(key);
ValueIndex++;
}
isfull = (state == 4 && ValueIndex >= b_len) || (state == 5 && ValueIndex >= p_len);
if (isfull)
{
LCD.setTextColor(ILI9341_WHITE);
LCD.setCursor(20, 140);
LCD.println("Please press '#'");
}
}
void eraseChar()
{
if (ValueIndex > 0)
{
LCD.setTextColor(ILI9341_WHITE);
ValueIndex--;
ID_Value[ValueIndex] = '\0';
LCD.fillScreen(ILI9341_BLACK);
LCD.setCursor(0, 0);
string msgVal = state == 4 ? "BIO ID" : state == 5 ? "Post ID" : "";
string msg = "Please enter the " + msgVal + "\n";
LCD.println(msg.c_str());
LCD.setCursor(0, 100);
LCD.println(ID_Value);
}
}
bool isCorrectBIO()
{
bool isCorrect = false;
for (JsonVariant value : FingerDatas.as<JsonArray>())
{
if (!value.isNull())
{
if (value["BioID"] != nullptr && strcmp(value["BioID"], ID_Value) == 0)
{
isCorrect = true;
SelectedVoter["BioID"] == value["BioID"];
SelectedVoter["FingerID"] == value["FingerID"];
SelectedVoter["FingerTemplate"] == value["FingerTemplate"];
SelectedVoter["Name"] == value["Name"];
SelectedVoter["PostID"] == value["PostID"];
}
}
}
return isCorrect;
}
bool isCorrectPostID()
{
return SelectedVoter["PostID"] == ID_Value;
}
void CheckPostID()
{
bool isvalid = FingerDatas.size() <= 0 || SelectedVoter.size() <= 0;
if (!isvalid)
{
bool validpost = isCorrectPostID();
if (validpost)
{
// goto voing
// print candidates
}
else
{
// PostIDRequest();
}
}
else
{
LCD.fillScreen(ILI9341_RED);
LCD.setCursor(0, 0);
LCD.println("Something Wrong Try Again\n");
delay(10000);
// BioIDRequest();
}
}
int cnt = 0;
void BioIDRequest()
{
memset(ID_Value, '\0', sizeof(ID_Value));
state = 4;
LCD.fillScreen(ILI9341_BLACK);
LCD.setCursor(0, 0);
LCD.println("Please enter the BIO ID\n");
LCD.print(cnt++);
//IDEntery(4);
}
void CheckBioID()
{
if (FingerDatas.size() <= 0)
{
GetVotersData();
}
bool iscrt = isCorrectBIO();
if (!iscrt)
{
LCD.fillScreen(ILI9341_BLACK);
LCD.setCursor(0, 0);
LCD.setTextColor(ILI9341_RED);
LCD.println("Invalid BIO ID\n");
delay(10000);
//BioIDRequest();
//change state
state = 1;
}
else
{
if (isAlredyVoted())
{
LCD.fillScreen(ILI9341_BLACK);
LCD.setTextSize(3);
LCD.setCursor(0, 0);
LCD.setTextColor(ILI9341_RED);
LCD.println("You are alredy voted!!!!\n");
}
else
{
// PostIDRequest();
state = 2;
}
}
}
void CorrectID()
{
if (state == 4 && ValueIndex == b_len)
{
CheckBioID();
}
else if (state == 5 && ValueIndex == p_len)
{
// CheckPostID();
}
}
void IDEntery(uint8_t _st)
{
state = _st;
char key = customKeypad.getKey();
switch (key)
{
case '#':
CorrectID();
break;
case '*':
eraseChar();
break;
default:
if (isDigit(key))
{
nextChar(key);
}
break;
}
}
void PostIDRequest()
{
memset(ID_Value, '\0', sizeof(ID_Value));
state = 2;
LCD.fillScreen(ILI9341_BLACK);
LCD.setCursor(0, 0);
LCD.println("Please enter the Post ID\n");
IDEntery(5);
}
void startVoting()
{
char key = customKeypad.getKey();
if (key != '\0')
{
switch (key)
{
case '#':
BioIDRequest();
break;
case '*':
initDisplay();
// getKeyValue();
break;
default:
LCD.fillScreen(ILI9341_BLACK);
LCD.setCursor(0, 20);
LCD.println("# - Start / Enter\n");
LCD.println("* - Cancel");
break;
}
}
}
int getPressedVoteBtn()
{
for (int i = 0; i < numButtons; i++)
{
int currentState = digitalRead(buttonPins[i]);
if (currentState == LOW)
{
while (digitalRead(buttonPins[i]) == LOW)
;
return i;
}
}
return -1;
}
int lastpressed = -1;
int GetVote()
{
int pressedVote = getPressedVoteBtn();
if (pressedVote != -1 && lastpressed != pressedVote)
{
Serial.print("Vote button ");
Serial.print(pressedVote + 1);
Serial.println(" pressed");
lastpressed = pressedVote;
// get who selected
return 1;
}
return -1;
}
void awaitCandidateSelection()
{
int voteRes = GetVote();
if (voteRes == 1)
{
}
else
{
// start again
}
}
void Voting()
{
state = 3;
if (Candidates.size() <= 0)
{
GetCandidateData();
}
LCD.fillScreen(ILI9341_BLACK);
LCD.setCursor(0, 0);
LCD.setTextSize(2);
int cnt = 0;
for (JsonVariant value : Candidates.as<JsonArray>())
{
if (!value.isNull())
{
const char *CandidateName = value["CandidateName"];
LCD.setCursor(0, cnt * 18);
LCD.println(CandidateName);
}
}
LCD.setCursor(0, cnt * 18);
LCD.println("Please select your candidate");
state = 5;
awaitCandidateSelection();
}
void getKeyValue()
{
{
switch (state)
{
case 0:
startVoting(); // done
break;
case 1:
BioIDRequest();
break;
case 2:
PostIDRequest();
break;
case 3:
Voting();
break;
case 4:
IDEntery(4);
break;
case 5:
awaitCandidateSelection();
break;
}
}
}
void setup()
{
Serial.begin(9600);
LCD.begin();
LCD.setRotation(1);
InitFirebase();
initDisplay();
InitPushBtn();
// get candidates
GetCandidateData();
GetVotersData();
ElectID = "E1";
}
void loop()
{
getKeyValue();
//}
// char key = customKeypad.getKey();
// if(key)
//{
// LCD.fillScreen(ILI9341_BLACK);
// LCD.setCursor(0, 0);
// LCD.println(key);
// LCD.println("..............");
//}
// LCD.fillScreen(ILI9341_BLACK);
// LCD.setCursor(0, 0);
// delay(50);
}