Skip to content

Instantly share code, notes, and snippets.

@rafabarzotto
Created November 16, 2020 20:03
Show Gist options
  • Save rafabarzotto/e5d9e1d2078511fb247a833a866af793 to your computer and use it in GitHub Desktop.
Save rafabarzotto/e5d9e1d2078511fb247a833a866af793 to your computer and use it in GitHub Desktop.
chopp_comentado.c
/*********************************************************************
*********************************************************************/
/*
SCK 18
MOSI 23
DC 19
RST 14
CS 5
*/
//Bibliotecas para conexao wifi
#ifdef ESP32
#include <WiFi.h>
#include <HTTPClient.h>
#else
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#endif
//###############################
#include <Arduino_JSON.h> //Biblioteca leitura de JSON
#include <SPI.h> //Biblioteca de comunicaçao serial - display/rfid
#include <Adafruit_GFX.h> //Biblioteca para plotar no display
#include <Adafruit_PCD8544.h> //Biblioteca funcionamento do display
#include <deprecated.h> //Bibiotecas RFID
#include <MFRC522.h> //Bibiotecas RFID
#include <MFRC522Extended.h> //Bibiotecas RFID
#include <require_cpp11.h> //Bibiotecas RFID
//Pinagem Display Nokia
#define BL 27
#define SCK 15
#define MOSI 2
#define DC 4
#define RST 13
#define CS 5
//Pinagem Leitor RFID
#define SS_PIN 21
#define RST_PIN 22
const char* ssid = "Escritorio_Barzotto"; //Nome Rede Wi-Fi
const char* password = ""; //Senha
String serverName = "http://192.168.10.81/chopp/php/"; //Servidor web
String resultHTTP;
int botao300ml = 12; //Pino Botao 300ml
int botao500ml = 14; //Pino Botao 500ml
int ledBotao300ml = 32; //Pino Rele LED Botao 300
int ledBotao500ml = 33; //Pino Rele LED Botao 300
int releValvula = 25; //Pino Rele Valvula Soneloide
byte sensorFluxo = 34; //Pino Sensor de Fluxo
int qtdEscolhida = 0; //Variavel para salvar escolha do tamanho do copo (300, 500)
String uidString; //Variavel para salvar o código lido do cartao RDID
float valor300; //Variavel salvar o valor vindo do banco ref copo 300ml
float valor500; //Variavel salvar o valor vindo do banco ref copo 300ml
int idCliente; //Variavel salvar o ID do Cliente vindo do banco
float saldoCliente; //Variavel salvar o saldo do cliente vindo do banco
float calibrationFactor = 7; //Variavel de calibração sensor de fluxo ()
volatile byte pulseCount; //Variavel de contagem de pulso do sensor de fluxo
float flowRate; // Variavel para salvar taxa de fluxo do sensor
unsigned int flowMilliLitres; //variavel para salvar a quantidade de mililitros contados no fluxo
unsigned long totalMilliLitres; //variavel para somar o total de fluxo passado em mL
unsigned long oldTime; //Variavel para salvar o tempo inicial
//Estados de Maquinas
enum enumState {
telaInicial,
rfidScan,
selecionaQuantidade,
liberaChopp,
aguardandoEncherCopo,
ativaSensorDeFluxo,
telaFinal,
telaErro
};
//Define estado inicial do sistema
enumState state = telaInicial;
Adafruit_PCD8544 display = Adafruit_PCD8544(SCK, MOSI, DC, CS, RST); //Instancia Bibliotecas do Display
//Adafruit_PCD8544 display = Adafruit_PCD8544(DC, CS, RST);
MFRC522 mfrc522(SS_PIN, RST_PIN); // Instancia Bibliotecas do RFID
//Inicia Sistema e Carrega Configuracoes Iniciais
void setup() {
Serial.begin(9600); //Seta velocidade serial
pinMode(botao300ml, INPUT_PULLUP); //Seta pino botao300 como entrada (leitura)
pinMode(botao500ml, INPUT_PULLUP); //Seta pino botao500 como entrada (leitura)
pinMode(sensorFluxo, INPUT_PULLUP); //Seta pino sensor de fluxo como entrada (leitura)
pinMode(ledBotao300ml, OUTPUT); //Seta pino led botao 300 como saída
pinMode(ledBotao500ml, OUTPUT); //Seta pino led botao 500 como saída
pinMode(releValvula, OUTPUT); //Seta pino rele valvula 300 como saída
digitalWrite(ledBotao300ml, LOW); //Seta estado inicial rele do led do botao 300 como Desligado
digitalWrite(ledBotao500ml, LOW); //Seta estado inicial rele do led do botao 500 como Desligado
digitalWrite(releValvula, LOW); //Seta estado inicial rele da valvula como Desligado
digitalWrite(sensorFluxo, LOW); //Seta estado inicial do sensor de fluxo como Desligado
pulseCount = 0; //Zera variaveis
flowRate = 0.0; //Zera variaveis
flowMilliLitres = 0; //Zera variaveis
totalMilliLitres = 0; //Zera variaveis
oldTime = 0; //Zera variaveis
display.begin(); //Inicia Display
SPI.begin(); // Inicia comunicacao serial
mfrc522.PCD_Init(); // Inicia Leitor RFIT MFRC522
Serial.println("RFID Pronto...");
Serial.println();
//display.setContrast(50);
display.display(); // mostra splashscreen padrao display
delay(3000);
//Inicia Conexao Wifi e mostra no display (Conectando)
WiFi.begin(ssid, password);
Serial.println("Conectando");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(2, 15);
display.print("Conectando...");
display.display();
//Aguarda ate que consiga conectar na wifi
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
//Se conectar, mostra no display o endereço IP
display.clearDisplay();
Serial.println("");
Serial.print("Conectado ao WiFi com o IP: ");
Serial.println(WiFi.localIP());
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(2, 15);
display.print(WiFi.localIP());
display.display();
delay(5000);
display.clearDisplay();
Serial.println("Pronto ...");
/*Configura interrupcao do sensor de fluxo, da prioriedade pra leitura do sensor, pra ter certeza que vai ler todos os pulsos
ler mais em: https://www.arduino.cc/reference/pt/language/functions/external-interrupts/attachinterrupt/
*/
attachInterrupt(sensorFluxo, pulseCounter, CHANGE);
}
void loop() {
//Inicia o LOOP do sistema, caso o estado de maquina mudar, cai no case referente e executa as instruçoes do estado definido
switch (state)
{
case telaInicial:
//Zera variaveis toda vez que entra na tela inicial (entende-se um como recomeço do processo)
qtdEscolhida = 0;
totalMilliLitres = 0;
idCliente = 0;
saldoCliente = 0;
//Desliga reles
digitalWrite(ledBotao300ml, LOW);
digitalWrite(ledBotao500ml, LOW);
digitalWrite(sensorFluxo, LOW);
//Mostra mensagem no display
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(12, 15);
display.println("Aguardando");
display.print(" Leitura..");
display.display();
delay(1000);
/*
Chama a funcao de carregar os valores do chopp.
Se o banco de dados retornar OK, muda estado de maquina para: rfidScan
Se o banco de dados estiver desligado, offline: muda estado do sistema de maquina para: telaErro
*/
if(carregarValores() == "ok"){
state = rfidScan;
} else {
state = telaErro;
}
break;
case rfidScan:
//Enquanto estiver executando o estado rfidScan, a funcão de leitura do cartao é acionada (ate que mude de estado)
RfidScan();
break;
case selecionaQuantidade:
//Enquanto estiver executando o estado selecionaQuantidade, a funcão de selecionarQuantidade é acionada
SelecionaQuantidade();
break;
case liberaChopp:
//Enquanto estiver executando o estado liberaChopp, a funcão de LiberaChopp é acionada
LiberaChopp();
break;
case ativaSensorDeFluxo:
//Enquanto estiver executando o estado ativaSensorDeFluxo, a funcão de AtivaSensorDeFluxo é acionada
AtivaSensorDeFluxo();
break;
case aguardandoEncherCopo:
//Enquanto estiver executando o estado aguardandoEncherCopo, a funcão de lerSensorFluxo é acionada
lerSensorFluxo();
break;
case telaFinal:
//Mostra mensagem no display, e volta para o estado inicial, para reiniciar o processo
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(8, 15);
display.print("Obrigado!!");
display.display();
display.clearDisplay();
delay(3000);
state = telaInicial;
break;
case telaErro:
//Mostra mensagem de erro no display, zera todas as variaveis e desliga os reles
qtdEscolhida = 0;
totalMilliLitres = 0;
idCliente = 0;
saldoCliente = 0;
digitalWrite(ledBotao300ml, LOW);
digitalWrite(ledBotao500ml, LOW);
digitalWrite(sensorFluxo, LOW);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(30, 10);
display.print("Erro");
display.setCursor(10, 20);
display.print("de Conexao");
display.setCursor(15, 30);
display.print("com o BD..");
display.display();
delay(2000);
display.clearDisplay();
break;
}
}
/*
Funcao que realiza a reitura do cartao via RFID (usando as bibliotecas necessarias).
*/
void RfidScan()
{
if ( ! mfrc522.PICC_IsNewCardPresent())
return;
if ( ! mfrc522.PICC_ReadCardSerial())
return;
//Executa funcao de conversao dos bytes lidos pelo RFID
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
}
/*
Essa funcao executa a leitura do cartao RFID atraves do MFRC522, e converte de HEX para DECIMAL
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
char message[bufferSize];
for (byte i = 0; i < bufferSize; i++) {
//Serial.print(buffer[i] < 0x10 ? ” 0″ : ” “);
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
Serial.print(" = ");
uidString = String(mfrc522.uid.uidByte[0]) + String(mfrc522.uid.uidByte[1]) + String(mfrc522.uid.uidByte[2]) + String(mfrc522.uid.uidByte[3]);
Serial.print(uidString);
Serial.println();
//Mostra no display o cod do cartao já convertido em DECIMAL
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(15, 15);
display.print(uidString);
display.display();
delay(3000);
display.clearDisplay();
/*
Chama a funcao para verificar se no banco de dados existe o código do cartao recem lido
Se retornar OK, executa a funcao de cartaoCadastrado()
Se retornar NOK, executa a funcao de cartaoNaoCadastrado() - E volta pra tela inicial
Se retornar qualquer coisa além de OK e NOK sinal que existe algum erro, muda o estado e seta como telaErro
*/
if (lerCartaoBanco(uidString) == "ok") {
cartaoCadastrado();
} else if (lerCartaoBanco(uidString) == "nok") {
cartaoNaoCadastrado();
} else {
state = telaErro;
}
// if (uidString == "4 21 145 138") {
// cartaoCadastrado();
// } else {
// cartaoNaoCadastrado();
// }
}
//Se cartao cadastrado, mostra mensagem para selecionar a quantidade e muda o estade de maquina para selecionaQuantidade
void cartaoCadastrado()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(13, 15);
display.println("Selecione");
display.setCursor(6, 25);
display.println("a Quantidade");
display.display();
delay(2000);
display.clearDisplay();
state = selecionaQuantidade;
}
//Se o cartao nao estiver cadastrado, simplesmente reinicia o processo mudando o estado de maquina para telaInicial
void cartaoNaoCadastrado()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(30, 15);
display.print("Nao");
display.setCursor(8, 25);
display.print("Cadastrado..");
display.display();
delay(2000);
display.clearDisplay();
state = telaInicial;
}
//Se o estado for para selecionar a quantidade, o a funcao selecionaQuantidade é ativada
void SelecionaQuantidade()
{
if (digitalRead(botao300ml) == HIGH) { //Verifica se apertou no botao 300
Serial.println("Apertou 300");
digitalWrite(ledBotao300ml, HIGH); //Se SIM, seta a variavel qtdEscolhida para 300 (para saber até quantos ML o sensor de fluxo deve ler)
qtdEscolhida = 300;
if (saldoCliente >= valor300) { // Antes de liberar o a valvula, verifica se o saldo do cliente salvo na variavel saldoCliente maior ou igual ao valor do copo escolhido
state = liberaChopp; // Se o saldo for suficiente muda o estado para liberarChopp
} else {
//Se o saldo nao for sufiente, mostra a mensagem na tela, e volta para o estado telaInicial
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(25, 15);
display.println("Saldo");
display.setCursor(0, 25);
display.print("Insuficiente..");
display.display();
delay(3000);
display.clearDisplay();
state = telaInicial;
}
}
if (digitalRead(botao500ml) == HIGH) { //Verifica se apertou no botao 500
Serial.println("Apertou 500");
digitalWrite(ledBotao500ml, HIGH);
qtdEscolhida = 500;
if (saldoCliente > valor500) {
state = liberaChopp;
} else {
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(25, 15);
display.println("Saldo");
display.setCursor(0, 25);
display.print("Insuficiente..");
display.display();
delay(3000); //Sleep for a second.
display.clearDisplay();
state = telaInicial;
}
}
else {
//Serial.println("Nao Apertou Nada");
}
}
/*
Quando a funcao libera chopp é ativada, mostra a quantidade escolhida atraves da variavel que foi salva a quantidadeEscolhida no display
manda sinal HIGH para o releValvula, (com a valvula aberta, muda o estado de maquina para ativaSensorDeFluxo)
*/
void LiberaChopp()
{
if(descontarSaldoBanco() == "ok"){
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(6, 15);
display.print(String(qtdEscolhida) + "ml");
display.display();
delay(2000);
display.clearDisplay();
digitalWrite(releValvula, HIGH);
state = ativaSensorDeFluxo;
} else {
state = telaErro;
}
}
/*
Quando a função é ativada, o pino do sensorDeFluxo é setado como HIGH, posibilitando a leitura de quanto fluxo de chopp passara no sensor
*/
void AtivaSensorDeFluxo()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(8, 15);
display.print("Encha seu copo");
display.display();
//delay(2000);
digitalWrite(sensorFluxo, HIGH);
display.clearDisplay();
state = aguardandoEncherCopo;
}
/*
Quando a funcão é ativada, inicia a leitura do sensor
*/
void AguardandoEncherCopo()
{
lerSensorFluxo();
}
void pulseCounter()
{
//Variavel de incremento de pulso (contado pelo sensor hall)
pulseCount++;
}
void lerSensorFluxo()
{
if ((millis() - oldTime) > 1000) //executa a contagem de pulsos uma vez por segundo
{
//desabilita a interrupcao para realizar a conversao do valor de pulsos
detachInterrupt(sensorFluxo);
/*
Como este loop pode não ser concluído exatamente em intervalos de 1 segundo, calculamos
o número de milissegundos que se passaram desde a última execução e usa-se
isso para dimensionar a saída. Também aplicamos o calibraçãoFactor para dimensionar a saída de fluxo
com base no número de pulsos por segundo dividios pela unidade de medida (litros / minuto em
neste caso) vindo do sensor.
*/
flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
//Atualiza o tempo variavel
oldTime = millis();
/*
Divide a taxa de fluxo de litros por minuto por 60, para determinar quantos litros
passou nesse sensor no intervalo de 1 segundo, multiplicar por 1000
para converter em mililitros
*/
flowMilliLitres = (flowRate / 60) * 1000;
// Acumula quantos mililitros passaram
totalMilliLitres += flowMilliLitres;
/*
Quando o total de mL que o sensor de fluxo contou for maior que a quantidade escolhida armazenada na variavel
a valvula é FECHADA
*/
if (totalMilliLitres > qtdEscolhida) {
//digitalWrite(releValvula, LOW);
state = telaFinal;
oldTime = 0;
digitalWrite(releValvula, LOW);
}
unsigned int frac;
/*
Mostra a taxa de fluxo via serial
*/
Serial.print("Pulsos: ");
Serial.print(pulseCount);
Serial.print("\t");
Serial.print("Taxa de Fluxo em Litros/min: ");
Serial.print(int(flowRate));
Serial.print("L/min");
Serial.print("\t");
Serial.print("Saída Total de Liquido: ");
Serial.print(totalMilliLitres);
Serial.println("mL");
Serial.print("\t");
Serial.print(totalMilliLitres / 1000);
Serial.print("L");
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(6, 15);
display.print(String(totalMilliLitres) + "ml");
display.display();
// Reseta o contado de pulso
pulseCount = 0;
// Habilita a interrupção novamente agora já que terminou de enviar a saída contada
attachInterrupt(sensorFluxo, pulseCounter, RISING);
}
}
//Funcao que faz a consulta no banco de dados, se o cod do cartao está presente no banco
String lerCartaoBanco(String codCartao) {
//Se o WiFi estiver conectado continua
if (WiFi.status() == WL_CONNECTED) {
String url = "getCartao.php?cod_cartao=" + codCartao; //Concatena URL: getCartao.php?cod_cartao=123123123
String url_full = serverName + url; //Concatena Endereco do SERVIDOR com URL http://192.168.10.81/chopp/php/getCartao.php?cod_cartao=123123123
const char* urlChar = url_full.c_str(); //Converte em a STRING URL em CHAR (FUNCAO HTTP SO FUNCIONA EM CHAR)
Serial.println(urlChar);
resultHTTP = httpGETRequest(urlChar); //Faz a chamada do metodo HTTP GET passando a URL e grava o resultado na variavel sensor resultHTTP
JSONVar myObject = JSON.parse(resultHTTP); //Grava o resultado como JSON, para facilitar o manuseio dos dados
if(resultHTTP != "erro"){ //Se na variavel estiver diferente de "erro" continua
if (myObject["success"]) { //Se na variavel estiver "sucesso"
idCliente = JSON.stringify(myObject["data"]["id"]).toInt(); //Recupera do JSON a ID do cliente e converte em int e grava na var idCliente (para usar posteriormente gravando no banco qual cliente deve diminuir saldo do banco)
saldoCliente = JSON.stringify(myObject["data"]["saldo"]).toFloat(); //Recupera do JSON o saldo do cliente e converte em float grava na variavel saldoCliente para depois poder verificar se o saldo do cliente é suficiente para escolha o valor do copo
//Mostra no display "Ola Cliente, seu saldo é:"
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 1);
display.println("Ola " + JSON.stringify(myObject["data"]["nome"]) + ",");
display.setTextSize(1);
display.setCursor(0, 10);
display.println("Seu saldo: ");
display.setCursor(0, 30);
display.println("R$:" + JSON.stringify(myObject["data"]["saldo"]));
display.display();
delay(4000);
display.clearDisplay();
return "ok"; //RETORNA OK para validar a FUNCAO cartaoCadastrado()
} else {
return "nok"; //RETORNA NOK para validar a FUNCAO cartaoNaoCadastrado()
}
} else {
return "erro"; //RETORNA ERRO para validar ERRO de banco
}
} else {
}
}
/*
Funcao que faz a consulta no banco de dados e carrega valores dos copos nas variaveis
para depois comparar se o saldo do cliente é suficiente para selecionar um copo
*/
String carregarValores() {
if (WiFi.status() == WL_CONNECTED) {
String url = "listaValores.php";
String url_full = serverName + url;
const char* urlChar = url_full.c_str();
Serial.println(urlChar);
resultHTTP = httpGETRequest(urlChar);
if(resultHTTP != "erro"){
JSONVar myObject = JSON.parse(resultHTTP);
valor300 = JSON.stringify(myObject["data"][0]["valor"]).toFloat();
valor500 = JSON.stringify(myObject["data"][1]["valor"]).toFloat();
Serial.println(valor300);
Serial.println(valor500);
return "ok";
} else {
return "erro";
}
} else {
}
}
/*
Funcao que chama o HTTP POST passando o CLIENTE e qual copo ele selecionou para
descontar no banco de dados o saldo do cliente, e registrar o consumo do cliente
*/
String descontarSaldoBanco() {
if (WiFi.status() == WL_CONNECTED) {
String url = "salvaConsumo.php";
String url_full = serverName + url;
const char* urlChar = url_full.c_str();
String dados = "id_copo=" + String(qtdEscolhida) + "&id_cliente=" + String(idCliente);
const char* dadosChar = dados.c_str();
Serial.println(dadosChar);
resultHTTP = httpPOST(urlChar, dadosChar);
if(resultHTTP != "erro"){
JSONVar myObject = JSON.parse(resultHTTP);
Serial.println(myObject);
return "ok";
} else {
return "erro";
}
}
}
/*
Funcao padrao HTTP GET
*/
String httpGETRequest(const char* serverName) {
HTTPClient http;
// Your IP address with path or Domain name with URL path
http.begin(serverName);
// Send HTTP POST request
int httpResponseCode = http.GET();
String payload = "{}";
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
payload = "erro";
}
// Free resources
http.end();
return payload;
}
/*
Funcao Padrao HTTP POST
*/
String httpPOST(const char* serverName, const char* httpRequestData) {
HTTPClient http;
// Your IP address with path or Domain name with URL path
http.begin(serverName);
// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
int httpResponseCode = http.POST(httpRequestData);
String payload = "{}";
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
payload = "erro";
}
// Free resources
http.end();
return payload;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment