Sorr about that, here's my complete code for your reference. Sorry for the long read, thanks!
#include <Adafruit_Thermal.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal_I2C.h>
#include <FirebaseESP8266.h>
#include "vglogoII.h"
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"
//Network
#include "ESP8266WiFi.h"
#include "NTPClient.h"
#include "WiFiUdp.h"
//Firebase
#define DB_URL "https://vg-wifi-kerberos-default-rtdb.asia-southeast1.firebasedatabase.app/"
#define FB_API_KEY "AIzaSyCIUI08MowggqoiRO8eh7PXGXTB_XB0SqM"
//Firebase and Database usage
FirebaseData fbd;
QueryFilter queryFilter;
FirebaseJson* fbJson;
FirebaseAuth fbauth;
FirebaseConfig fbconfig;
String fbCode = "";
//Wifi, Date & Time
const char* ssid = "wifiname";
const char* password = "wifipassword";
WiFiUDP ntpUDP;
const long utcOffsetInSeconds = 28800;
NTPClient timeClient(ntpUDP, "time.nist.gov", utcOffsetInSeconds);
//Pin assignment
const int BTN_LED_PIN = 0;
const int COIN_PIN = 2;
const int BUTTON_PIN = 3;
const int BUZZ_PIN = 12;
const int COIN_SET_PIN = 15;
const int TX_PIN = 14; //Green Wire
const int RX_PIN = 16; //Yellow Wire
LiquidCrystal_I2C lcd(0x27, 16, 2);
SoftwareSerial mySerial(RX_PIN, TX_PIN);
Adafruit_Thermal printer(&mySerial);
//Button variables
volatile int btnState = 0;
volatile bool btnPressed = false;
volatile bool btnDisabled = false;
//Countdown variables
const long interval = 1000;
unsigned long previousMillis = 0;
volatile int countdown = 21;
int printCountdown = 6;
bool countdownStarted = false;
bool printCountdownStarted = false;
//Ethernet variables
String currentMacAddress = "";
String currentIpAddress = "";
//Other variables
volatile int totalAmount = 0;
int resetCounter = 20;
volatile int lcdState = 1;
//Execute-once Boolean lcd clearing variables
bool tier0Clear = true;
bool tierIClear = true;
bool tierIIClear = true;
bool tierIVClear = true;
bool tierVClear = true;
bool tierVIClear = true;
bool firstEntry = true;
void IRAM_ATTR coinInterrupt() {
if(btnState == 1) {
countdown = 21;
totalAmount++;
lcdState = 2;
}
}
void IRAM_ATTR btnInterrupt() {
static unsigned long lastExec = 0;
unsigned long currentExec = millis();
if(currentExec - lastExec > 500 && !btnDisabled) {
btnPressed = true;
btnDisabled = true;
btnState++;
}
lastExec = currentExec;
}
void connectWifi() {
if(WiFi.status() != WL_CONNECTED) { // Connect to Wi-Fi network with SSID and password
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
lcd.setCursor(0,0);
lcd.print("Connecting Wifi");
delay(600);
lcd.clear();
}
WiFi.setAutoReconnect(true);
WiFi.persistent(true);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
}
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
pinMode(BTN_LED_PIN, OUTPUT);
pinMode(COIN_PIN, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(COIN_SET_PIN, OUTPUT);
pinMode(BUZZ_PIN, OUTPUT);
digitalWrite(BTN_LED_PIN, LOW);
digitalWrite(COIN_SET_PIN, LOW);
digitalWrite(BUZZ_PIN, LOW);
attachInterrupt(digitalPinToInterrupt(COIN_PIN), coinInterrupt, RISING);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), btnInterrupt, FALLING);
lcd.init();
lcd.clear();
lcd.backlight();
printer.begin();
delay(1000L);
connectWifi();
timeClient.begin();
fbconfig.api_key = FB_API_KEY;
fbconfig.database_url = DB_URL;
if(Firebase.signUp(&fbconfig, &fbauth, "", "")){
Serial.println("Firebase signup ok");
Firebase.begin(&fbconfig, &fbauth);
sendLog(getDate(), getDate() +"-" +getTime() +": Firebase sign up ok;");
buzz();
}
else{
Serial.printf("%s\n", fbconfig.signer.signupError.message.c_str());
sendLog(getDate(), getDate() +"-" +getTime() +": Firebase error; " +fbconfig.signer.signupError.message.c_str());
}
fbconfig.token_status_callback = tokenStatusCallback;
Firebase.begin(&fbconfig, &fbauth);
Firebase.reconnectWiFi(true);
sendLog(getDate(), getDate() +"-" +getTime() +": System boot up;");
}
void loop() {
unsigned long currentMillis = millis();
// if WiFi is down, try reconnecting
if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >= 180000)) {
Serial.print(millis());
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.begin(ssid, password);
previousMillis = currentMillis;
}
switch(lcdState) {
case 1: //Home state
lcd.setCursor(1, 0);
lcd.print("VGWifi Hotspot");
lcd.setCursor(2, 1);
lcd.print(" ");
lcd.setCursor(2, 1);
lcd.print("Press button");
digitalWrite(BTN_LED_PIN, HIGH);
delay(500);
lcd.setCursor(2, 1);
lcd.print(" ");
digitalWrite(BTN_LED_PIN, LOW);
delay(500);
break;
case 2: //Counter state
if(totalAmount <= 0 && firstEntry) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Insert coins now");
firstEntry = false;
}
lcd.setCursor(0, 0);
if(totalAmount > 0 && totalAmount < 5) {
if(tier0Clear) {
lcd.setCursor(0,0);
lcd.print(" ");
tier0Clear = false;
}
lcd.setCursor(0,0);
lcd.print("0 MINS");
} else if(totalAmount >= 5 && totalAmount < 10) {
if(tierIClear) {
lcd.setCursor(0,0);
lcd.print(" ");
tierIClear = false;
}
lcd.setCursor(0,0);
lcd.print("30 MINS");
} else if(totalAmount >= 10 && totalAmount < 15) {
if(tierIIClear) {
lcd.print(" ");
tierIIClear = false;
}
lcd.setCursor(0,0);
lcd.print("1 HOUR");
} else if(totalAmount >= 15 && totalAmount < 25) {
lcd.print("3 HOURS");
} else if(totalAmount >= 25 && totalAmount < 35) {
if(tierIVClear) {
lcd.print(" ");
tierIVClear = false;
}
lcd.setCursor(0,0);
lcd.print("1 DAY");
} else if(totalAmount >= 35 && totalAmount <50) {
if(tierVClear) {
lcd.print(" ");
tierVClear = false;
}
lcd.setCursor(0,0);
lcd.print("3 DAYS");
} else if(totalAmount >= 50) {
if(tierVIClear) {
lcd.print(" ");
tierVIClear = false;
}
lcd.setCursor(0,0);
lcd.print("7 DAYS");
}
lcd.setCursor(0, 1);
if(totalAmount > -1) {
lcd.print("P");
lcd.print(totalAmount);
lcd.print(".00");
}
break;
}
if(btnPressed) {
switch(btnState) {
case 1:
enableCoinSlot();
btnPressed = false;
countdownStarted = true;
lcdState = 2;
digitalWrite(BTN_LED_PIN, LOW);
break;
case 2:
printCountdown = 6;
printCountdownStarted = false;
finishTransaction();
break;
}
}
//Countdown for insert coins
if(countdownStarted && (currentMillis - previousMillis >= interval)) {
previousMillis = currentMillis;
countdown--;
if(countdown < 10) {
lcd.setCursor(15, 1);
lcd.print(" ");
}
lcd.setCursor(11, 1); // Set cursor position
lcd.print("(");
lcd.print(countdown);
lcd.print("s)");
}
if(printCountdownStarted && (currentMillis - previousMillis >= interval)) {
previousMillis = currentMillis;
printCountdown--;
lcd.setCursor(15, 0);
lcd.print(printCountdown);
}
if(countdown <= 0) {
if(totalAmount >= 5) {
displayPrintPrompt();
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Not enough coins");
lcd.setCursor(0, 1);
lcd.print("Minimum is P5.00");
disableCoinSlot();
delay(3000);
lcdState = 1;
if(totalAmount > 0) {
finishTransaction();
}
lcd.clear();
totalAmount = 0;
btnState = 0;
btnDisabled = false;
}
countdown = 21;
countdownStarted = false;
}
if(printCountdown <= 0) {
finishTransaction();
printCountdown = 6;
printCountdownStarted = false;
}
}
String getDate() {
timeClient.update();
time_t epochTime = timeClient.getEpochTime();
struct tm *ptm = gmtime ((time_t *)&epochTime);
int currentMonth = ptm->tm_mon+1;
int monthDay = ptm->tm_mday;
int currentYear = ptm->tm_year+1900;
String date = String(currentMonth) +"-" +monthDay +"-" +currentYear;
return date;
}
String getTime() {
timeClient.update();
return String(timeClient.getFormattedTime());
}
void displayPrintPrompt() {
printCountdownStarted = true;
lcdState = 3;
btnDisabled = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Print voucher?");
lcd.setCursor(0, 1);
lcd.print("Press button");
disableCoinSlot();
digitalWrite(BTN_LED_PIN, HIGH);
}
void enableCoinSlot() {
digitalWrite(COIN_SET_PIN, HIGH);
}
void disableCoinSlot() {
digitalWrite(COIN_SET_PIN, LOW);
}
void finishTransaction() {
disableCoinSlot();
getVoucher(totalAmount);
btnPressed = false;
digitalWrite(BTN_LED_PIN, LOW);
delay(5000);
buzz();
lcd.clear();
btnDisabled = false;
btnState = 0;
lcdState = 1;
totalAmount = 0;
resetCounter--;
if(resetCounter == 0) {
sendLog(getDate(), getDate() +"-" +getTime() +": System reboot;");
ESP.reset();
}
}
void getVoucher(int amt) {
String date = getDate();
String time = getTime();
String desc;
String valid;
String fbdpath;
String code;
String log;
int change;
int tier;
if(amt > 0 && amt < 5) {
tier = 0;
code = "-";
} else {
if(amt >= 5 && amt < 10) {
valid = "30 MINS";
tier = 5;
fbdpath = "/P05V/";
} else if(amt >= 10 && amt < 15) {
valid = "1 HOUR";
tier = 10;
fbdpath = "/P10V/";
} else if(amt >= 15 && amt < 25) {
valid = "3 HOURS";
tier = 15;
fbdpath = "/P15V/";
} else if(amt >= 25 && amt < 35) {
valid = "1 DAY";
tier = 25;
fbdpath = "/P25V/";
} else if(amt >= 35 && amt <50) {
valid = "3 DAYS";
tier = 35;
fbdpath = "/P35V/";
} else if(amt >= 50) {
valid = "7 DAYS";
tier = 50;
fbdpath = "/P50V/";
}
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("Generating");
lcd.setCursor(3, 1);
lcd.print("voucher...");
if(Firebase.ready()) {
queryFilter.orderBy("$key");
queryFilter.limitToLast(1);
if(Firebase.getJSON(fbd, fbdpath, queryFilter)) {
fbJson = fbd.to<FirebaseJson *>();
size_t length = fbJson->iteratorBegin();
size_t i = 0;
FirebaseJson::IteratorValue element;
element = fbJson->valueAt(i);
code = element.value.c_str();
code.replace('"', ' ');
Serial.println("Key: " +String(element.key.c_str()));
Serial.println("Value: "+String(element.value.c_str()));
fbJson->iteratorEnd();
fbJson->clear();
Serial.printf("Delete element from db: %s\n", Firebase.deleteNode(fbd, fbdpath + element.key.c_str()) ? "ok" : fbd.errorReason().c_str());
}
}
}
change = amt-tier;
if(change > 0) {
String chg = String(change);
if(tier == 0) {
desc = "Get your P" +chg +".00 back";
log = date +"-" +time +": User inserted insufficient amount of coins. Return P" +chg +".00.";
} else {
desc = "Your change is P" +chg +".00";
log = date +"-" +time +": Purchase of P" +String(tier) +".00 voucher with code: " +code +" completed; User's change is P" +chg +".00.";
}
} else {
log = date +"-" +time +": Purchase of P" +String(tier) +".00 voucher with code: " +code +" completed;";
}
lcd.clear();
lcd.print(valid);
lcd.print(" Voucher:");
lcd.setCursor(4, 1);
lcd.print(code);
printer.wake();
printVoucher(code, tier, valid, desc, date, time);
sendLog(date, log);
firstEntry = true;
}
void printVoucher(String code, int amount, String valid, String change, String date, String time) {
printer.wake();
String tier = " (P" +String(amount) +".00)";
printer.wake();
printer.justify('C');
printer.setFont('C');
//printer.setSize('M');
//printer.println("VG Wifi");
printer.setSize('S');
printer.println("");
printer.println("Voucher Code:");
printer.setSize('L');
printer.println(code);
printer.setSize('S');
printer.println("");
printer.setSize('M');
printer.print(valid);
printer.println(tier);
printer.boldOff();
printer.setSize('S');
printer.println(change);
printer.println(date);
printer.print(time);
printer.println(F("\n"));
printer.println(F("\n"));
printer.setDefault();
tier0Clear = true;
tierIClear = true;
tierIIClear = true;
tierIVClear = true;
tierVClear = true;
tierVIClear = true;
}
void sendLog(String date, String log) {
String logPath = "/logs/" +date;
Serial.printf("Send log: %s\n", Firebase.pushString(fbd, logPath, log) ? "ok" : fbd.errorReason().c_str());
}
void buzz() {
digitalWrite(BUZZ_PIN, HIGH);
delay(1000);
digitalWrite(BUZZ_PIN, LOW);
}