/*
Wanderson José - 2023
O código abaixo está comentado em portugûes,
porém todas as variáveis e constantes estão
escritas em inglês
*/
// Biblioteca responsável pelos leds
#include <Adafruit_NeoPixel.h>
// Bibliotecas responsáveis pelo firebase
#include <Firebase_ESP_Client.h>
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"
// Biblioteca do wifi
#include <WiFi.h>
// Biblioteca responsável pela data e hora
#include <time.h>
// Bibliotecas padrões
#include <Arduino.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Define o pin dos leds
#define LEDS_PIN 32
// Define a quantidade de leds
#define NUM_PIXELS 15
// Define o pin do trig para o sensor ultrassônico
#define TRIG_PIN 33
// Define o pin do echo para o sensor ultrassônico
#define ECHO_PIN 25
// Define o pin do botão
#define BUTTON_PIN 27
// Define o pin do piezo (responsável pela barulho)
#define PIEZO_PIN 14
// Nome da rede wifi
#define WIFI_SSID ""
// Senha da rede wifi
#define WIFI_PASSWORD ""
// Chave de api do firebase
#define API_KEY ""
// Link do banco de dados do firebase
#define DATABASE_URL ""
// Configurações do firebase
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
// Configurações para que seja possível pega a
// data e a hora pelo servidor ntp
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -10800; // Brasília time zone (UTC-3)
const int daylightOffset_sec = 0;
// Guarda um indentificador único para o esp32
char uuid[] = "00000000-00000000-11111111-111111111";
// Guarda o estado de cadastro do firebase
// Em caso de sucesso ao tentar se registrar
// é alterada para true
// Por padrão definida como false
bool signupOK = false;
// Guarda o caminho em que dado é guardado no firebase
char path[120];
char path2[120];
// Guarda o estado atual da vaga
char current_state;
// Guarda o ultimo estado da vaga
char last_state;
// Guarda o valor da duração da onda do sensor ultrassônico
long duration;
// Guarda o valor da distância capitada pelo sensor ultrassônico
int distance;
// Guarda o estado atual do botão
int current_state_button;
// Guarda o tipo da vaga
// Por padrão definida como normal
char type = 'n';
// Usada para garantir que o estado de ocupada será mandada apenas uma
// vez em caso de não houver alteração de estado
int occupied_state_counter = 0;
// Usada para garantir que o estado de vazio será mandada apenas uma
// vez em caso de não houver alteração de estado
int void_state_counter = 0;
// A variável count é usada para contar quantas
// ciclos o veículo continuou na área vermelha
int count;
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_PIXELS, LEDS_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BUTTON_PIN, INPUT);
Serial.begin(9600);
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();
/* Assign the api key (required) */
config.api_key = API_KEY;
/* Assign the RTDB URL (required) */
config.database_url = DATABASE_URL;
/* Sign up */
while (signupOK != true) {
Serial.println("Sign up firebase...");
if (Firebase.signUp(&config, &auth, "", "")) {
Serial.println("Firebase connected");
signupOK = true;
} else {
Serial.printf("%s\n", config.signer.signupError.message.c_str());
}
}
/* Assign the callback function for the long running token generation task */
config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h
Firebase.begin(&config, &auth);
Firebase.reconnectWiFi(true);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
pixels.begin();
// A variável ultiza da função getDate para definir a data
String date = getDate();
// Caso a data ainda não tenha sido atualizada (o valor
// padrão inicial para a data é 31-12-1969) continua no
// while até que a data seja atualizada
while (date == "31-12-1969") {
Serial.println("Synchronizing date...");
date = getDate();
delay(2000);
}
// Define o caminho que será ultilizado para salva
// os dados no firebase
sprintf(path, "data/%s/%s", uuid, getDate());
Serial.println(path);
sprintf(path2, "data/%s/info", uuid);
}
void loop() {
// Capitação do estado do botão (1 para pressionado e 0 para não pressionado)
current_state_button = digitalRead(BUTTON_PIN);
// Verifica se o botão foi pressionado, em caso de sim,
// verifica qual o tipo de vaga atual e modifica a mesma
// alternando entre vaga normal e especial
if (current_state_button == 1) {
if (type == 'n') {
type = 's';
Serial.println("\nVaga tipo normal mofificada para especial!");
if (Firebase.RTDB.setString(&fbdo, path2, "s")) {
Serial.println("Data send with success!");
Serial.println("PATH: " + fbdo.dataPath());
} else {
Serial.println("Failed to send data!");
Serial.println("REASON: " + fbdo.errorReason());
}
delay(500);
} else {
type = 'n';
Serial.println("\nVaga tipo especial mofificada para normal!");
if (Firebase.RTDB.setString(&fbdo, path2, "n")) {
Serial.println("Data send with success!");
Serial.println("PATH: " + fbdo.dataPath());
} else {
Serial.println("Failed to send data!");
Serial.println("REASON: " + fbdo.errorReason());
}
delay(500);
}
}
if (type == 'n') {
// Para a vaga normal o led do meio deve ser da cor verde
pixels.setPixelColor(7, pixels.Color(0, 255, 0));
} else {
// Para vaga especial o led do meio deve ser da cor azul
pixels.setPixelColor(7, pixels.Color(0, 0, 255));
}
// Define o brilho padrão dos leds
pixels.setBrightness(50);
// Ativação do sensor ultrassônico
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(5);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Capitação da duração da onda do sensor
duration = pulseIn(ECHO_PIN, HIGH);
// Capitação da distância em cm
distance = duration * 0.0351 / 2;
// Usa a função checkLeds para definir a cor dos
// leds de acordo com a distância e checar o estado
// da vaga
checkLeds(distance);
delay(250);
// Limpa os leds (exceto o do meio) por meio da função clearLeds
clearLeds();
// Checa os estado atual e o último estado para descobrir
// se houve alteração no estado
if (last_state == 'v') {
if (occupied_state_counter == 0) {
if (Firebase.ready()) {
// Converte o current_state (char) para uma string
String current_state_str(current_state);
// Converte o type (char) para uma string
String type_str(type);
FirebaseJson json;
json.add("state", current_state_str);
json.add("type", type_str);
json.add("time", getTime());
// Tenta enviar os dados, em caso de positivo,
// imprimi mensagem de sucesso e o caminho ultilizado
// e em caso de falha imprime mensagem de erro e o erro
if (Firebase.RTDB.pushJSON(&fbdo, path, &json)) {
Serial.println("Data send with success!");
Serial.println("PATH: " + fbdo.dataPath());
// Defini que o estado de vaga ocupada já foi enviado
occupied_state_counter = 1;
// Libera para que o estado de vaga vazia possa ser enviado
void_state_counter = 0;
} else {
Serial.println("Failed to send data!");
Serial.println("REASON: " + fbdo.errorReason());
}
}
}
} else {
if (void_state_counter == 0) {
if (Firebase.ready()) {
// Converte o current_state (char) para uma string
String current_state_str(current_state);
// Converte o type (char) para uma string
String type_str(type);
FirebaseJson json;
json.add("state", current_state_str);
json.add("type", type_str);
json.add("time", getTime());
// Tenta enviar os dados, em caso de positivo,
// imprimi mensagem de sucesso e o caminho ultilizado
// e em caso de falha imprime mensagem de erro e o erro
if (Firebase.RTDB.pushJSON(&fbdo, path, &json)) {
Serial.println("Data send with success!");
Serial.println("PATH: " + fbdo.dataPath());
// Defini que o estado de vaga vazia já foi enviado
void_state_counter = 1;
// Libera para que o estado de vaga vazia possa ser enviado
occupied_state_counter = 0;
} else {
Serial.println("Failed to send data!");
Serial.println("REASON: " + fbdo.errorReason());
}
}
}
}
}
// Função responsável por trazer a data
String getDate() {
time_t now = time(nullptr); // Pega o horário atual
struct tm* timeinfo = localtime(&now); // Converte o horário para uma struct tm
char date[11]; // Cria a string para armazenar a data formatada
strftime(date, 11, "%d-%m-%Y", timeinfo); // Formata a data no formato "DD-MM-AAAA"
return String(date);
}
// Função responsável por trazer a hora
String getTime() {
time_t now = time(nullptr); // Pega o horário atual
struct tm* timeinfo = localtime(&now); // Converte o horário para uma struct tm
char time[10]; // Cria a string para armazenar a hora formatada
strftime(time, 10, " %H:%M:%S", timeinfo); // Formata a hora no formato " HH:MM:SS"
return String(time);
}
// Função responsável por checar o que deve ser exibido
// na fita de led de acordo com a distância
void checkLeds(int dist) {
// Define o estado atual da vaga como vazia (void)
current_state = 'v';
// Defini o último estado como ocupado (occupied)
last_state = 'o';
// Caso a distância seja maior/igual a 25 ou
// menor igual a 25
if (dist <= 100 && dist >= 70) {
// Define o estado atual da vaga como vazia (void)
current_state = 'v';
// Defini o último estado como ocupado (occupied)
last_state = 'o';
// Caso o veículo saia da área vermelha a contagem
// de ciclos é zerada
count = 0;
// Altera a cor dos leds 0,1, 13, 14 para a cor verde
pixels.setPixelColor(0, pixels.Color(0, 255, 0));
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
pixels.setPixelColor(13, pixels.Color(0, 255, 0));
pixels.setPixelColor(14, pixels.Color(0, 255, 0));
}
// Caso a distância seja maior/igual a 20 ou
// menor igual a 25
if (dist < 70 && dist >= 50) {
// Define o estado atual da vaga como vazia (void)
current_state = 'v';
// Defini o último estado como ocupado (occupied)
last_state = 'o';
// Caso o veículo saia da área vermelha a contagem
// de ciclos é zerada
count = 0;
// Altera a cor dos leds 0,1,13,14 para a cor verde
pixels.setPixelColor(0, pixels.Color(0, 255, 0));
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
pixels.setPixelColor(13, pixels.Color(0, 255, 0));
pixels.setPixelColor(14, pixels.Color(0, 255, 0));
// Altera a cor dos leds 2,3,11,12 para uma cor verde/amarela
pixels.setPixelColor(2, pixels.Color(102, 255, 51));
pixels.setPixelColor(3, pixels.Color(102, 255, 51));
pixels.setPixelColor(11, pixels.Color(102, 255, 51));
pixels.setPixelColor(12, pixels.Color(102, 255, 51));
}
if (dist < 50 && dist >= 30) {
// Define o estado atual da vaga como vazia (void)
current_state = 'v';
// Defini o último estado como ocupado (occupied)
last_state = 'o';
// Caso o veículo saia da área vermelha a contagem
// de ciclos é zerada
count = 0;
// Altera a cor dos leds 0,1,13,14 para a cor verde
pixels.setPixelColor(0, pixels.Color(0, 255, 0));
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
pixels.setPixelColor(13, pixels.Color(0, 255, 0));
pixels.setPixelColor(14, pixels.Color(0, 255, 0));
// Altera a cor dos leds 2,3,11,12 para uma cor verde/amarela
pixels.setPixelColor(2, pixels.Color(102, 255, 51));
pixels.setPixelColor(3, pixels.Color(102, 255, 51));
pixels.setPixelColor(11, pixels.Color(102, 255, 51));
pixels.setPixelColor(12, pixels.Color(102, 255, 51));
// Altera a cor dos leds 4,5,9,10 para a cor amarela
pixels.setPixelColor(4, pixels.Color(255, 255, 0));
pixels.setPixelColor(5, pixels.Color(255, 255, 0));
pixels.setPixelColor(9, pixels.Color(255, 255, 0));
pixels.setPixelColor(10, pixels.Color(255, 255, 0));
}
// Área vermelha (muito proxímo ao sensor)
if (dist < 30 && dist > 15) {
// Checa se o veículo está a menos de x vezes
// na área vermelha, em caso de positivo, continua
// apitando
if (count < 10) {
tone(PIEZO_PIN, 523, 100);
delay(1000);
noTone(PIEZO_PIN);
count++;
}
// Checa se o veículo está a mais de x vezes na área
// vermelha, em caso de positivo altera a vaga para
// ocupada e em caso de não aumenta a contagem e faz
// com que os leds pisquem em vermelho
if (count >= 10) {
// Define o led do meio como vermelho
pixels.setPixelColor(7, pixels.Color(255, 0, 0));
// Define o estado atual da vaga como ocupada (occupied)
current_state = 'o';
// Defini o último estado como vazio (void)
last_state = 'v';
} else {
int x;
// Altera a cor de todos (exceto o do meio) os leds para vermelho
for (x = 0; x <= 14; x++) {
if (x != 7) {
pixels.setPixelColor(x, pixels.Color(255, 0, 0));
}
}
}
}
if (dist <= 15) {
// Checa se o veículo está a menos de x vezes
// na área vermelha, em caso de positivo, continua
// apitando
if (count < 10) {
tone(PIEZO_PIN, 523, 100);
delay(500);
noTone(PIEZO_PIN);
count++;
}
// Checa se o veículo está a mais de x vezes na área
// vermelha, em caso de positivo altera a vaga para
// ocupada e em caso de não aumenta a contagem e faz
// com que os leds pisquem em vermelho
if (count >= 10) {
// Define o led do meio como vermelho
pixels.setPixelColor(7, pixels.Color(255, 0, 0));
// Define o estado atual da vaga como ocupada (occupied)
current_state = 'o';
// Defini o último estado como vazio (void)
last_state = 'v';
} else {
int x;
// Altera a cor de todos (exceto o do meio) os leds para vermelho
for (x = 0; x <= 14; x++) {
if (x != 7) {
pixels.setPixelColor(x, pixels.Color(255, 0, 0));
}
}
}
}
// Método que exibir o que é definido nos leds
pixels.show();
}
// Função responsável por limpar os leds a cada ciclo
// exceto o led do meio
void clearLeds() {
int i;
for(i = 0; i < NUM_PIXELS; i++) {
if (i != 7) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
}
}
pixels.show();
}
Comments