Here is the whole code.
lato and roller are fonts and a image used in the tft library.
as for the schematics, i dont have one. I have 4 buttons connected at the pins 21,22,36,37.
A sd card module is connected like this:
CS Pin 33
SCK Pin 25
MOSI Pin 26
MISO Pin 27
There is nothing else beside an external pul up resistor on pins 36 and 37
Thank you
#include <NTPClient.h>
#include <WiFi.h>
#include <time.h>
#include <WiFiUdp.h>
#include <AsyncTelegram2.h>
#include <WiFiClientSecure.h>
#include <Timezone.h> // https://github.com/JChristensen/Timezone
#include <TFT_eSPI.h> // Graphics and font library
#include <SPI.h>
#include <sqlite3.h>
#include "FS.h"
#include "SD.h"
#include "roller.h"
#include "lato14.h"
#include "lato22.h"
#include "lato30.h"
#include "lato38.h"
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
TFT_eSprite img = TFT_eSprite(&tft);
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define HSPI_MISO 27
#define HSPI_MOSI 26
#define HSPI_SCLK 25
#define HSPI_CS 33
#define ROTA 36
#define ROTB 37
#define ENTERA 21
#define ENTERB 22
#define led 2
int rc;
sqlite3_stmt *res;
int rec_count = 0;
const char *tail;
sqlite3 *db1;
char *zErrMsg = 0;
SPIClass spiSD(HSPI);
File myFile;
bool initial = 1;
bool getdata = false;
String sql;
unsigned long tStamp1;
String user_name[30];
int user_id[30];
//int user_balanceCurr[30];
//int user_balanceOverall[30];
int movements_id[50];
String movements_productname[50];
String movements_date[50];
int movements_move[50];
String product_name[30];
int product_id[30];
int product_balance[30];
int productbalanceoverall ;
//int balance_idproduct[30];
String balance_nameproduct[30];
int balance_curr[30];
int balance_overall[30];
String setting_name[4];
int numusers = 0;
int numproducts = 0;
int nummovements = 0;
int numbalance = 0;
int curruser = 0;
int currproduct = 0;
int currmovement = 0;
int olduser = 0;
int currsetting = 0;
int productcounter = 0;
int state1;
int state2;
int currpage = 0;
/* 00 = main
10 = select drink
15 = quantity
18 = confirm
20 = menu
30 = history names
40 = history
50 = status
60 = reset confirm
*/
#define TFT_GREY 0x5AEB
#define IWIDTH 240
#define IHEIGHT 135
WiFiClientSecure client;
/***************TELEGRAM*******************************/
#define MYTZ "CET-1CEST-2,M3.5.0/2,M10.5.0/3"
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = 0;
struct tm timeinfo;
AsyncTelegram2 myBot(client);
ReplyKeyboard myReplyKbd; // reply keyboard object helper
const char* token = "TOKEN:TOKEN"; // REPLACE myToken WITH YOUR TELEGRAM BOT TOKEN
/***************END TELEGRAM***************************/
//WIFI VARS
WiFiUDP ntpUDP;
unsigned long time_now = 0;
int period = 1800000;
String ssid;
String password;
//TIME VARS
int Hour;
int Min;
int Sec;
int Day;
int DayInMonth;
int Month;
int Year;
unsigned long currTime;
unsigned long lastTime;
String currDateTime;
String currDate;
static tm getDateTimeByParams(long time) {
struct tm *newtime;
const time_t tim = time;
newtime = localtime(&tim);
return *newtime;
}
static String getDateTimeStringByParams(tm *newtime, char* pattern = (char *)"%d/%m/%Y %H:%M:%S") {
char buffer[30];
strftime(buffer, 30, pattern, newtime);
return buffer;
}
static tm getEpochTmByParams(long time, char* pattern = (char *)"%d/%m/%Y %H:%M:%S") {
// struct tm *newtime;
tm newtime;
newtime = getDateTimeByParams(time);
return (newtime);
}
static String getEpochStringByParams(long time, char* pattern = (char *)"%d/%m/%Y %H:%M:%S") {
// struct tm *newtime;
tm newtime;
newtime = getDateTimeByParams(time);
return getDateTimeStringByParams(&newtime, pattern);
}
int GTMOffset = 0; // SET TO UTC TIME
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", GTMOffset * 60 * 60, 60 * 60 * 1000);
// Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time
Timezone CE(CEST, CET);
void setup() {
Serial.println( esp_get_free_heap_size() );
//Init settings list
setting_name[0] = "Historie";
setting_name[1] = "Status";
setting_name[2] = "Bestand";
setting_name[3] = "Reset";
pinMode(HSPI_CS, OUTPUT);
pinMode(ROTA, INPUT_PULLUP );
pinMode(ROTB, INPUT_PULLUP );
pinMode(ENTERA, INPUT_PULLUP);
pinMode(ENTERB, INPUT_PULLUP);
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println( esp_get_free_heap_size() );
sqlite3_initialize();
spiSD.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_CS);
if (!SD.begin(HSPI_CS, spiSD)) {
Serial.println("Card Mount Failed");
return;
}
else
{
Serial.println("Card ok!");
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println("No SD card attached");
return;
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
Serial.println( esp_get_free_heap_size() );
if (openDb("/sd/db.db3", &db1))
return;
Serial.println( esp_get_free_heap_size() );
initialize();
delay(500);
wificonnect();
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
timeClient.begin();
delay ( 1000 );
if (timeClient.update()) {
Serial.println ( "Adjust local clock" );
unsigned long epoch = timeClient.getEpochTime();
setTime(epoch);
} else {
Serial.println ( "NTP Update not WORK!!" );
}
xTaskCreatePinnedToCore( fTickerTask, "fTickerTask", 2000, NULL, 2, NULL, 1 );
Serial.println( esp_get_free_heap_size() );
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setSwapBytes(true);
img.setSwapBytes(true);
img.createSprite(IWIDTH, IHEIGHT);
img.fillSprite(TFT_BLACK);
Serial.println( esp_get_free_heap_size() );
//Set certficate, session and some other base client properies
client.setCACert(telegram_cert);
// Set the Telegram bot properies
myBot.setUpdateTime(1000);
myBot.setTelegramToken(token);
Serial.print("\nTest Telegram connection... ");
myBot.begin() ? Serial.println("OK") : Serial.println("NOK");
myReplyKbd.addButton("Abrechnung");
myReplyKbd.enableResize();
Serial.println( esp_get_free_heap_size() );
}
void fTickerTask( void * pvParameters )
{
for (;;)
{
Serial.println( "tick");
vTaskDelay(1000);
}
vTaskDelete( NULL );
}
void wificonnect() {
// Connect to WiFi access point.
Serial.println(); Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid.c_str(), password.c_str());
// WiFi.config(ip, gateway, subnet);
int startTime = millis();
while (WiFi.status() != WL_CONNECTED && (millis() - startTime) <= 10000) {
delay(500);
Serial.print(".");
}
Serial.println();
digitalWrite(led, LOW);
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
/*
Startpage
*/
if ((WiFi.status() != WL_CONNECTED) and (millis() > time_now + period)) {
time_now = millis();
wificonnect();
}
if (WiFi.status() == WL_CONNECTED)
{
// a variable to store telegram message data
TBMessage msg;
// if there is an incoming message...
if (myBot.getNewMessage(msg))
{
Serial.println("ok2");
String tgReply;
static String document;
switch (msg.messageType)
{
case MessageDocument :
break;
case MessageQuery:
break;
default:
if ( msg.text == "Abrechnung")
{
Serial.println("Abrechnung....");
myBot.sendMessage(msg, "Abrechnung ... ... ...", myReplyKbd);
}
break;
}
}
}
if ((currpage == 0 and not initial) or currpage == 30 or currpage == 60)
{
curruser = counter(curruser, 0, numusers - 1, true);
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
if (currpage == 0)
{
if (numproducts = 1)
{
currpage = 15;
currproduct = 0;
}
else
{
currpage = 10;
}
}
else if (currpage == 30)
{
getdata = true;
currpage = 40;
}
else
{
currpage = 65;
}
productcounter = 0;
}
if (action == 2)
{
if (currpage == 0)
{
//change page. RETURN
currpage = 20;
}
else if (currpage == 30)
{
currpage = 20;
}
else
{
currpage = 20;
}
}
img.fillSprite(TFT_BLACK);
img.pushImage(5, 6, 170, 123, roller);
img.setTextColor(TFT_WHITE);
img.setTextDatum(0);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato38);
w = img.textWidth(user_name[curruser]);
h = img.fontHeight();
img.drawString(user_name[curruser], 88 - w / 2, IHEIGHT / 2 - h / 2);
img.setTextColor(TFT_GREY);
if (curruser > 0)
{
img.setFreeFont(&lato22);
w = img.textWidth(user_name[curruser - 1]);
h = img.fontHeight();
img.drawString(user_name[curruser - 1], 88 - w / 2, 23 - h / 2);
}
else
{
img.setFreeFont(&lato22);
w = img.textWidth(user_name[numusers - 1]);
h = img.fontHeight();
img.drawString(user_name[numusers - 1], 88 - w / 2, 23 - h / 2);
}
if (curruser < numusers - 1)
{
img.setFreeFont(&lato22);
w = img.textWidth(user_name[curruser + 1]);
h = img.fontHeight();
img.drawString(user_name[curruser + 1], 88 - w / 2, 112 - h / 2);
}
else
{
img.setFreeFont(&lato22);
w = img.textWidth(user_name[0]);
h = img.fontHeight();
img.drawString(user_name[0], 88 - w / 2, 112 - h / 2);
}
if (currpage == 0)
{
img.setTextColor(TFT_WHITE);
img.setTextDatum(1);
int i;
for (i = 0; i < numproducts; i++)
{
img.drawString(product_name[i], 210, 10 + i * 40, 2);
img.drawNumber(product_balance[i], 210, 25 + i * 40, 2);
if (i < numproducts - 1)
{
img.drawLine(190, 45 + i * 40, 230, 45 + i * 40, TFT_WHITE);
}
}
}
img.setTextDatum(0);
img.pushSprite(0, 0);
}
/*
Page Select Drink
*/
if (currpage == 10)
{
currproduct = counter(currproduct, 0, numproducts - 1, true);
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
currpage = 15;
productcounter = 0;
}
if (action == 2)
{
//change page. RETURN
currpage = 0;
}
img.fillSprite(TFT_BLACK);
img.pushImage(5, 6, 170, 123, roller);
img.setTextColor(TFT_WHITE);
img.setTextDatum(0);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato38);
w = img.textWidth(product_name[currproduct]);
h = img.fontHeight();
img.drawString(product_name[currproduct], 88 - w / 2, IHEIGHT / 2 - h / 2);
img.setTextColor(TFT_GREY);
if (currproduct > 0)
{
img.setFreeFont(&lato22);
w = img.textWidth(product_name[currproduct - 1]);
h = img.fontHeight();
img.drawString(product_name[currproduct - 1], 88 - w / 2, 23 - h / 2);
}
else
{
img.setFreeFont(&lato22);
w = img.textWidth(product_name[numproducts - 1]);
h = img.fontHeight();
img.drawString(product_name[numproducts - 1], 88 - w / 2, 23 - h / 2);
}
if (currproduct < numproducts - 1)
{
img.setFreeFont(&lato22);
w = img.textWidth(product_name[currproduct + 1]);
h = img.fontHeight();
img.drawString(product_name[currproduct + 1], 88 - w / 2, 112 - h / 2);
}
else
{
img.setFreeFont(&lato22);
w = img.textWidth(product_name[0]);
h = img.fontHeight();
img.drawString(product_name[0], 88 - w / 2, 112 - h / 2);
}
img.setTextColor(TFT_WHITE);
img.setTextDatum(1);
int i;
for (i = 0; i < numproducts; i++)
{
img.drawString(product_name[i], 210, 10 + i * 40, 2);
img.drawNumber(product_balance[i], 210, 25 + i * 40, 2);
if (i < numproducts - 1)
{
img.drawLine(190, 45 + i * 40, 230, 45 + i * 40, TFT_WHITE);
}
}
img.setTextDatum(0);
img.pushSprite(0, 0);
}
/*
Page Quantity Drink
*/
if (currpage == 15)
{
productcounter = counter(productcounter, -20, 0, false);
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
currpage = 18;
}
if (action == 2)
{
if (numproducts > 1)
{
//change page. RETURN
currpage = 10;
}
else
{
currpage = 0;
}
}
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato38);
h = img.fontHeight();
w = img.textWidth(user_name[curruser]);
img.drawString(user_name[curruser], 5, 10);
img.setFreeFont(&lato22);
h = img.fontHeight();
w = img.textWidth(product_name[currproduct]);
img.drawString(product_name[currproduct], 85, 65);
img.drawNumber(abs(productcounter), 10, 70, 7);
img.setFreeFont(&lato22);
if (productcounter > 0)
{
img.drawString("hinzugefugt", 101, 100);
img.fillRect(188, 102, 2, 3, TFT_WHITE);
img.fillRect(193, 102, 2, 3, TFT_WHITE);
}
if (productcounter < 0)
{
img.drawString("genommen", 100, 100);
}
img.pushSprite(0, 0);
}
/*
Page Confirm Quantity Drink
*/
if (currpage == 18)
{
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
//save the data to the database...
sql = "insert into movements ('iduser','idproduct','date','move') values ('";
sql += user_id[curruser];
sql += "','";
sql += product_id[currproduct];
sql += "','";
sql += currDate;
sql += "','";
sql += productcounter;
sql += "');";
rc = db_exec(db1, sql.c_str());
sql = "update products set balance = balance + ";
sql += productcounter;
sql += " where id = ";
sql += product_id[currproduct];
sql += ";";
rc = db_exec(db1, sql.c_str());
/* sql = "insert into balance (iduser, idproduct, balancecurr, balanceoverall) SELECT ";
sql += user_id[curruser];
sql += ", ";
sql += product_id[currproduct];
sql += ", 0, 0 ";
sql += "WHERE NOT EXISTS(SELECT 1 FROM balance WHERE iduser='";
sql += user_id[curruser];
sql += "' AND idproduct='";
sql += product_id[currproduct];
sql += "');";*/
sql = "INSERT OR IGNORE INTO balance (iduser, idproduct, balancecurr, balanceoverall) VALUES( ";
sql += user_id[curruser];
sql += ", ";
sql += product_id[currproduct];
sql += ", 0, 0);";
rc = db_exec(db1, sql.c_str());
if (rc != SQLITE_OK) {
String resp = "Failed to fetch data: ";
resp += sqlite3_errmsg(db1);
Serial.println(resp.c_str());
return;
}
sql = "update balance set balanceCurr = balanceCurr + ";
sql += productcounter;
sql += ", balanceOverall = balanceOverall + ";
sql += productcounter;
sql += " where iduser = ";
sql += user_id[curruser];
sql += ";";
rc = db_exec(db1, sql.c_str());
product_balance[currproduct] += productcounter;
// user_balanceCurr[curruser] += productcounter;
// user_balanceOverall[curruser] += productcounter;
currpage = 0;
}
if (action == 2)
{
//change page. RETURN
currpage = 15;
}
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato30);
h = img.fontHeight();
w = img.textWidth(user_name[curruser]);
img.drawString(user_name[curruser], 5, 10);
img.setFreeFont(&lato22);
h = img.fontHeight();
w = img.textWidth(product_name[currproduct]);
img.drawString(product_name[currproduct], 40, 60);
img.drawNumber(abs(productcounter), 10, 60);
img.setFreeFont(&lato22);
if (productcounter > 0)
{
img.drawString("hinzugefugt", 111, 60);
// img.fillRect(157,102,2,3,TFT_WHITE);
// img.fillRect(162,102,2,3,TFT_WHITE);
}
if (productcounter < 0)
{
img.drawString("genommen", 110, 60);
}
img.setFreeFont(&lato14);
img.drawString("<-Zuruck", 10, 115);
img.drawString("Bestatigen->", 140, 115);
img.pushSprite(0, 0);
}
/*
Page Settings
*/
if (currpage == 20)
{
currsetting = counter(currsetting, 0, 4 - 1, true);
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
if (currsetting == 0)
{
currmovement = 0;
currpage = 30; //Historie
}
if (currsetting == 1)
{
getdata = true;
currpage = 50; //Stand
}
if (currsetting == 2)
{
currpage = 70; //Bestand
productbalanceoverall = product_balance[0];
}
if (currsetting == 3)
{
currpage = 60; //Zurücksetzen Bestätigen
}
currsetting = 0;
}
if (action == 2)
{
//change page. RETURN
currpage = 0;
}
img.fillSprite(TFT_BLACK);
img.pushImage(5, 6, 170, 123, roller);
img.setTextColor(TFT_WHITE);
img.setTextDatum(0);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato38);
w = img.textWidth(setting_name[currsetting]);
h = img.fontHeight();
img.drawString(setting_name[currsetting], 88 - w / 2, IHEIGHT / 2 - h / 2);
img.setTextColor(TFT_GREY);
if (currsetting > 0)
{
img.setFreeFont(&lato22);
w = img.textWidth(setting_name[currsetting - 1]);
h = img.fontHeight();
img.drawString(setting_name[currsetting - 1], 88 - w / 2, 23 - h / 2);
}
else
{
img.setFreeFont(&lato22);
w = img.textWidth(setting_name[4 - 1]);
h = img.fontHeight();
img.drawString(setting_name[4 - 1], 88 - w / 2, 23 - h / 2);
}
if (currsetting < 4 - 1)
{
img.setFreeFont(&lato22);
w = img.textWidth(setting_name[currsetting + 1]);
h = img.fontHeight();
img.drawString(setting_name[currsetting + 1], 88 - w / 2, 112 - h / 2);
}
else
{
img.setFreeFont(&lato22);
w = img.textWidth(setting_name[0]);
h = img.fontHeight();
img.drawString(setting_name[0], 88 - w / 2, 112 - h / 2);
}
img.pushSprite(0, 0);
}
/*
Page Historie
*/
if (currpage == 40)
{
if (getdata)
{
getdata = false;
//get the movements of the user form the DB
sql = "select m.id, p.name, m.date, m.move from movements as m left join products as p on p.id = m.idproduct where m.iduser = '";
sql += user_id[curruser];
sql += "' order by m.id desc limit 50";
//reset the arrays
int i;
for (i = 0; i < 50; i++)
{
movements_id[i] = 0;
movements_productname[i] = "";
movements_date[i] = "";
movements_move[i] = 0;
}
rc = sqlite3_prepare_v2(db1, sql.c_str(), sql.length() + 1, &res, &tail);
if (rc != SQLITE_OK) {
String resp = "Failed to fetch data: ";
resp += sqlite3_errmsg(db1);
Serial.println(resp.c_str());
return;
}
rec_count = 0;
nummovements = 0;
while (sqlite3_step(res) == SQLITE_ROW) {
movements_id[rec_count] = sqlite3_column_int(res, 0);
movements_productname[rec_count] = (const char *) sqlite3_column_text(res, 1);
movements_date[rec_count] = (const char *) sqlite3_column_text(res, 2);
movements_move[rec_count] = sqlite3_column_int(res, 3);
nummovements++;
rec_count++;
}
sqlite3_finalize(res);
}
currmovement = counter(currmovement, 0, nummovements - 5, false);
// curruser = counter(curruser, 0, numusers - 5, false);
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
currpage = 0; //Main page
}
if (action == 2)
{
//change page. RETURN
currsetting = 0;
currpage = 30;
}
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE);
img.setTextDatum(0);
img.setTextSize(1); // Font size scaling is x1
int w;
int h1;
img.setFreeFont(&lato30);
h1 = img.fontHeight();
img.drawString(user_name[curruser], 10, 5);
//img.drawNumber(nummovements, 150, 5);
int i;
int cnt = 0;
for (i = currmovement; i < nummovements; i++)
{
cnt ++;
img.setFreeFont(&lato14);
int h2;
h2 = img.fontHeight();
int ypos = h1 + 2 + h2 * (cnt - 1) + 10;
img.drawNumber(movements_id[i], 0, ypos);
img.drawString(movements_date[i], 25, ypos);
img.drawString(movements_productname[i], 140, ypos);
img.drawNumber(movements_move[i], 210, ypos);
}
img.pushSprite(0, 0);
}
/*
Page Stand
*/
if (currpage == 50)
{
if (getdata)
{
getdata = false;
//get the movements of the user form the DB
sql = "select p.name, b.balancecurr, b.balanceoverall from balance as b left join products as p on p.id = b.idproduct where b.iduser = '";
sql += user_id[curruser];
sql += "' order by b.idproduct asc";
//reset the arrays
int i;
for (i = 0; i < 30; i++)
{
balance_nameproduct[i] = "";
balance_curr[i] = 0;
balance_overall[i] = 0;
}
rc = sqlite3_prepare_v2(db1, sql.c_str(), sql.length() + 1, &res, &tail);
if (rc != SQLITE_OK) {
String resp = "Failed to fetch data: ";
resp += sqlite3_errmsg(db1);
Serial.println(resp.c_str());
return;
}
rec_count = 0;
numbalance = 0;
while (sqlite3_step(res) == SQLITE_ROW) {
balance_nameproduct[rec_count] = (const char *) sqlite3_column_text(res, 0);
balance_curr[rec_count] = sqlite3_column_int(res, 1);
balance_overall[rec_count] = sqlite3_column_int(res, 2);
numbalance++;
rec_count++;
}
sqlite3_finalize(res);
}
curruser = counter(curruser, 0, numusers - 1, true);
int action = exitconfirm();
if (curruser != olduser)
{
olduser = curruser;
getdata = true;
}
if (action == 1)
{
//change page. ENTER
currpage = 0; //Main page
}
if (action == 2)
{
//change page. RETURN
currsetting = 0;
currpage = 20;
}
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE);
img.setTextDatum(0);
img.setTextSize(1); // Font size scaling is x1
int w;
int h1;
img.setFreeFont(&lato30);
h1 = img.fontHeight();
img.drawString(user_name[curruser], 10, 5);
//img.drawNumber(nummovements, 150, 5);
img.setFreeFont(&lato14);
int h2;
h2 = img.fontHeight();
img.drawString("Akt.", 112, h1 + 2);
img.drawString("Ges.", 182, h1 + 2);
int i;
for (i = 0; i < numproducts; i++)
{
int ypos = h1 + 8 + h2 * i + 10;
img.drawString(balance_nameproduct[i], 10, ypos);
// img.drawNumber(balance_idproduct[i], 90, ypos);
img.drawNumber(balance_curr[i], 120, ypos);
img.drawNumber(balance_overall[i], 190, ypos);
}
img.pushSprite(0, 0);
}
/*
Page 60 is on Page 10
*/
/*
Page Confirm Quantity Drink Total
*/
if (currpage == 65)
{
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
sql = "update balance set balancecurr = 0 where iduser = ";
sql += user_id[curruser];
sql += " and idproduct = ";
sql += product_id[0];
sql += ";";
Serial.println(sql);
rc = db_exec(db1, sql.c_str());
// product_balance[0] = productbalanceoverall;
currpage = 0;
}
if (action == 2)
{
//change page. RETURN
currpage = 60;
}
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato22);
h = img.fontHeight();
img.drawString("Bestand fur ", 5, 10);
img.drawString(user_name[curruser], 5, 40);
img.drawString("zuruck setzen?", 5, 70);
img.setFreeFont(&lato14);
img.drawString("<-Zuruck", 10, 115);
img.drawString("Bestatigen->", 140, 115);
img.pushSprite(0, 0);
}
/*
Page Quantity Drink Total
*/
if (currpage == 70)
{
productbalanceoverall = counter(productbalanceoverall, 0, 150, false);
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
currpage = 75;
}
if (action == 2)
{
currpage = 20;
}
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato22);
h = img.fontHeight();
// w = img.textWidth(balance_overall[0]);
img.drawString("Akt. Bestand:", 5, 10);
img.drawNumber(product_balance[0], 185, 10);
img.drawString("Neuer Bestand:", 5, 50);
img.drawNumber(productbalanceoverall, 185, 50);
img.setFreeFont(&lato14);
img.drawString("<-Zuruck", 10, 115);
img.drawString("Bestatigen->", 140, 115);
img.pushSprite(0, 0);
}
/*
Page Confirm Quantity Drink Total
*/
if (currpage == 75)
{
int action = exitconfirm();
if (action == 1)
{
//change page. ENTER
sql = "update products set balance = ";
sql += productbalanceoverall;
sql += " where id = ";
sql += product_id[0];
sql += ";";
Serial.println(sql);
rc = db_exec(db1, sql.c_str());
product_balance[0] = productbalanceoverall;
currpage = 0;
}
if (action == 2)
{
//change page. RETURN
currpage = 70;
}
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE);
img.setTextSize(1); // Font size scaling is x1
int w;
int h;
img.setFreeFont(&lato22);
h = img.fontHeight();
img.drawString("Bestand von ", 5, 10);
img.drawNumber(product_balance[0], 155, 10);
img.drawString("auf ", 5, 40);
img.drawNumber(productbalanceoverall, 48, 40);
img.drawString("andern? ", 100, 40);
img.setFreeFont(&lato14);
img.drawString("<-Zuruck", 10, 115);
img.drawString("Bestatigen->", 140, 115);
img.pushSprite(0, 0);
}
/*
INIT
*/
updatetime();
}
/*
---------------------------------------------------------------------------------------
FUNCTIONS
---------------------------------------------------------------------------------------
*/
void initialize()
{
if (initial) {
initial = 0;
sql = "Select * from user order by id asc";
rc = sqlite3_prepare_v2(db1, sql.c_str(), sql.length() + 1, &res, &tail);
if (rc != SQLITE_OK) {
String resp = "Failed to fetch data: ";
resp += sqlite3_errmsg(db1);
Serial.println(resp.c_str());
return;
}
rec_count = 0;
numusers = 0;
while (sqlite3_step(res) == SQLITE_ROW) {
user_id[rec_count] = sqlite3_column_int(res, 0);
user_name[rec_count] = (const char *) sqlite3_column_text(res, 1);
// user_balanceCurr[rec_count] = sqlite3_column_int(res, 2);
// user_balanceOverall[rec_count] = sqlite3_column_int(res, 3);
numusers++;
rec_count++;
}
sqlite3_finalize(res);
sql = "Select * from products order by id asc";
rc = sqlite3_prepare_v2(db1, sql.c_str(), sql.length() + 1, &res, &tail);
if (rc != SQLITE_OK) {
String resp = "Failed to fetch data: ";
resp += sqlite3_errmsg(db1);
Serial.println(resp.c_str());
return;
}
rec_count = 0;
numproducts = 0;
while (sqlite3_step(res) == SQLITE_ROW) {
product_id[rec_count] = sqlite3_column_int(res, 0);
product_name[rec_count] = (const char *) sqlite3_column_text(res, 1);
product_balance[rec_count] = sqlite3_column_int(res, 2);
numproducts++;
rec_count++;
}
sqlite3_finalize(res);
sql = "Select * from settings where setting = 'ssid'";
rc = sqlite3_prepare_v2(db1, sql.c_str(), sql.length() + 1, &res, &tail);
if (rc != SQLITE_OK) {
String resp = "Failed to fetch data: ";
resp += sqlite3_errmsg(db1);
Serial.println(resp.c_str());
return;
}
while (sqlite3_step(res) == SQLITE_ROW) {
ssid = (const char *) sqlite3_column_text(res, 2);
}
sqlite3_finalize(res);
sql = "Select * from settings where setting = 'password'";
rc = sqlite3_prepare_v2(db1, sql.c_str(), sql.length() + 1, &res, &tail);
if (rc != SQLITE_OK) {
String resp = "Failed to fetch data: ";
resp += sqlite3_errmsg(db1);
Serial.println(resp.c_str());
return;
}
while (sqlite3_step(res) == SQLITE_ROW) {
password = (const char *) sqlite3_column_text(res, 2);
}
sqlite3_finalize(res);
}
}
void updatetime()
{
currTime = millis();
if (currTime - lastTime > 1000)
{
lastTime = currTime;
// "%d/%m/%Y %H:%M:%S"
//static String getEpochStringByParams(long time, char* pattern = (char *)"%d/%m/%Y %H:%M:%S"){
Hour = getEpochTmByParams(CE.toLocal(now())).tm_hour;
Min = getEpochTmByParams(CE.toLocal(now())).tm_min;
Sec = getEpochTmByParams(CE.toLocal(now())).tm_sec;
Day = getEpochTmByParams(CE.toLocal(now())).tm_wday;
Year = getEpochTmByParams(CE.toLocal(now())).tm_year;
if (Year < 120 )
{
currDate = "---";
}
else
{
currDateTime = getEpochStringByParams(CE.toLocal(now()));
currDate = currDateTime.substring(0, 10);
}
//Serial.println(currDate);
/* timeClient.update();
Serial.println(CE.locIsDST(timeClient.)));
Hour = timeClient.getHours();
Min = timeClient.getMinutes();
Sec = timeClient.getSeconds();
Day = timeClient.getDay();*/
/* Serial.print(" H1: ");
Serial.print(Hl);
Serial.print(" S1: ");
Serial.println(Sl);
Serial.print(SecondsLeft );
Serial.print(", ");
Serial.print(daysOfTheWeek[timeClient.getDay()]);
Serial.print(", ");
Serial.print(timeClient.getHours());
Serial.print(":");
Serial.print(timeClient.getMinutes());
Serial.print(":");
Serial.println(timeClient.getSeconds());
Serial.print("DAY: ");
Serial.println(timeClient.getDay());
//Serial.println(timeClient.getFormattedTime());*/
}
}
int counter(int currval, int minval, int maxval, bool wrap)
{
if (minval > maxval)
{
maxval = minval;
}
bool in1;
bool in2;
in1 = digitalRead(ROTA); // read the input pin
in2 = digitalRead(ROTB); // read the input pin
if (not in1 and in2)
{
if (state1 == 0)
{
currval++;
state1 = 1; //busy
if (currval > maxval) {
if (wrap)
{
currval = minval;
}
else
{
currval = maxval;
}
}
}
}
if (in1 and not in2)
{
if (state1 == 0)
{
currval--;
state1 = 1; //busy
if (currval < minval) {
if (wrap)
{
currval = maxval;
}
else
{
currval = minval;
}
}
}
}
if (in1 and in2)
{
state1 = 0;
}
return currval;
}
int exitconfirm()
{
bool in1;
bool in2;
in1 = digitalRead(ENTERA); // read the input pin
in2 = digitalRead(ENTERB); // read the input pin
int ret = 0;
unsigned long tNow = millis();
if (not in1 and in2 and state2 == 0 and tNow - tStamp1 > 300)
{
state2 = 1;
ret = 1;
//Serial.println("ENTER! >>");
}
if (in1 and in2 and state2 == 0)
{
state2 = 1;
ret = 2;
//Serial.println("Return <<!");
}
if (not in1 and not in2 and state2 > 0 and tNow - tStamp1 > 300)
{
tStamp1 = millis();
state2 = 0;
}
return ret;
}
const char* data = "Callback function called";
static int callback(void *data, int argc, char **argv, char **azColName) {
int i;
Serial.printf("%s: ", (const char*)data);
for (i = 0; i < argc; i++) {
Serial.printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
Serial.printf("\n");
return 0;
}
int openDb(const char *filename, sqlite3 **db) {
int rc = sqlite3_open(filename, db);
if (rc) {
Serial.printf("Can't open database: %s\n", sqlite3_errmsg(*db));
return rc;
} else {
Serial.printf("Opened database successfully\n");
}
return rc;
}
int db_exec(sqlite3 * db, const char *sql) {
Serial.println(sql);
long start = micros();
int rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if (rc != SQLITE_OK) {
Serial.printf("SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
Serial.printf("Operation done successfully\n");
}
Serial.print(F("Time taken:"));
Serial.println(micros() - start);
return rc;
}
void listDir(fs::FS & fs, const char * dirname, uint8_t levels) {
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels) {
listDir(fs, file.name(), levels - 1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void createDir(fs::FS & fs, const char * path) {
Serial.printf("Creating Dir: %s\n", path);
if (fs.mkdir(path)) {
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS & fs, const char * path) {
Serial.printf("Removing Dir: %s\n", path);
if (fs.rmdir(path)) {
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
void readFile(fs::FS & fs, const char * path) {
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while (file.available()) {
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS & fs, const char * path, const char * message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
if (file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS & fs, const char * path, const char * message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file) {
Serial.println("Failed to open file for appending");
return;
}
if (file.print(message)) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
void renameFile(fs::FS & fs, const char * path1, const char * path2) {
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
void deleteFile(fs::FS & fs, const char * path) {
Serial.printf("Deleting file: %s\n", path);
if (fs.remove(path)) {
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
void testFileIO(fs::FS & fs, const char * path) {
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if (file) {
len = file.size();
size_t flen = len;
start = millis();
while (len) {
size_t toRead = len;
if (toRead > 512) {
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for (i = 0; i < 2048; i++) {
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}