Using Firebase and esp32 to send parking spot information

The project sends vacancy data to a realtime database in firebase where it is possible to view all the data.

BeginnerShowcase (no instructions)2 days44
Using Firebase and esp32 to send parking spot information

Things used in this project

Hardware components

ESP32
Espressif ESP32
Speciffically used ESP32-WROOM-32U, recommend looking out for versions with the needed pins.
×1
Solderless Breadboard Full Size
Solderless Breadboard Full Size
A wider breadboard is recommended for ease of use.
×1
WS2812B Digital RGB LED Flexi-Strip 144 LED - 1 Meter
Seeed Studio WS2812B Digital RGB LED Flexi-Strip 144 LED - 1 Meter
Only 15 LED units used in this project.
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
Through Hole Resistor, 470 ohm
Through Hole Resistor, 470 ohm
×2
Capacitor 1000 µF
Capacitor 1000 µF
1000µF / 25V version used.
×1
Buzzer
Buzzer
×1
Rotary potentiometer (generic)
Rotary potentiometer (generic)
×1
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
In our project, this is replaced by the big blue button. Any switch with digital input should work.
×1
Jumper wires (generic)
Jumper wires (generic)
More or less 40 jumper wires, with 7 of them being male-to-female ones.
×40

Software apps and online services

Arduino IDE
Arduino IDE
Firebase
Google Firebase

Hand tools and fabrication machines

Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Code

esp32-firebase-parking-sensor

C/C++
/*
  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();
}

Credits

WANDERSON JOSE SANTOS DA SILVA

WANDERSON JOSE SANTOS DA SILVA

0 projects • 0 followers
Lázaro Santos

Lázaro Santos

0 projects • 0 followers

Comments

Add projectSign up / Login