Table of Contents

ESP32 Customizable Parking Sensor

1. Introduction

The “ESP32 Customizable Parking Sensor” project integrates an ESP32 microcontroller with a distance sensor, a buzzer, and an SDCard module to create a versatile parking assistance system. The core functionality involves storing music tracks on the SDCard and playing them through the buzzer. However, what sets this project apart is its user-friendly Web UI, which enables users to select their preferred music track. Additionally, a distance sensor enhances the functionality by adjusting the melody's playback speed based on the proximity of obstacles. As the distance to an obstacle decreases, the melody plays at a faster pace, providing real-time feedback to the user. This project not only offers practical assistance in parking situations but also showcases the capabilities of the ESP32 microcontroller in creating customizable and interactive solutions.

2. Hardware Components and Design

3. Software

// Load Wi-Fi library
#include <WiFi.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"
 
char *current_durations;
short *current_melody;
int current_size, current_note;
 
const char *network_ssid = "<MY-SSID>";
const char *network_password = "<MY-PASS>";
 
WiFiServer web_server(80);
String http_header;
 
unsigned long current_time_ms = millis();
unsigned long previous_time_ms = 0;
const long timeout_ms = 2000;
 
const int trigger_pin = 33;
const int echo_pin = 32;
const int buzzer_pin = 17;
 
#define SOUND_SPEED_CM_PER_US 0.034
#define CM_TO_INCH_CONVERSION 0.393701
 
long pulse_duration_us;
float distance_cm;
float distance_inch;
 
char file_names[32][32];
short file_melody[32][32];
char file_duration[32][32];
char file_mdsize[32];
int file_count;
 
void setup() {
    Serial.begin(115200);
    if(!SD.begin(5)){
        Serial.println("Card Mount Failed");
        return;
    }
 
    File root = SD.open("/");
    if(!root){
      return;
    }
 
    if(!root.isDirectory()){
     return;
    }
 
    File file = root.openNextFile();
    while(file) {
        int idx = 0;
        while(file.available()){
          file_duration[file_count][idx] = file.read();
          idx++;
        }
 
        file_mdsize[file_count] = idx;
 
        strcpy(file_names[file_count++], file.name());
        char *dot = strchr(file_names[file_count], '.');
        *dot = '\0';
 
        file.close();
        file = root.openNextFile();
        idx = 0;
        while(file.available()){
          file_melody[file_count][idx] = file.read();
          idx++;
        }
        file_count++;
 
        file.close();
        file = root.openNextFile();
    }
 
    pinMode(buzzer_pin, OUTPUT);
    pinMode(trigger_pin, OUTPUT);
    pinMode(echo_pin, INPUT);
    WiFi.begin(network_ssid, network_password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
    }
    web_server.begin();
    current_melody = file_melody[0];
    current_durations = file_duration[0];
    current_size = file_mdsize[0];
}
 
#define MIN_VALUE(a, b) (a > b ? b : a)
 
void play_note(int note) {
    long note_duration = 1000 / (int)current_durations[note] - (int)(50 - MIN_VALUE((int)distance_cm, 50));
 
    tone(buzzer_pin, (int)current_melody[note], note_duration);
    int pause_between_notes = note_duration * 1.30;
    delay(pause_between_notes);
    noTone(buzzer_pin);
}
 
unsigned long distance_probe_interval;
 
void update_distance(void) {
    digitalWrite(trigger_pin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigger_pin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigger_pin, LOW);
    pulse_duration_us = pulseIn(echo_pin, HIGH);
    distance_cm = pulse_duration_us * SOUND_SPEED_CM_PER_US / 2;
}
 
void loop() {
    WiFiClient client = web_server.available();
    int curr_file;
 
    if (client) {
        current_time_ms = millis();
        previous_time_ms = current_time_ms;
        String current_line = "";
        while (client.connected() && current_time_ms - previous_time_ms <= timeout_ms) {
            current_time_ms = millis();
            if (client.available()) {
                char c = client.read();
                http_header += c;
                if (c == '\n') {
                    if (current_line.length() == 0) {
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-type:text/html");
                        client.println("Connection: close");
                        client.println();
 
                        char req[100];
                        int i;
                        for (i = 0; i < file_count; i++) {
                            sprintf(req, "GET /%s/on", file_names[i]);
                            if (http_header.indexOf(req) >= 0) {
                                current_melody = file_melody[i];
                                current_durations = file_duration[i];
                                current_size = file_mdsize[i];
                                current_note = 0;
                                curr_file = i;
                                break;
                            }
                        }
 
                        client.println("<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><link rel=\"icon\" href=\"data:,\"><link href=\"https://fonts.googleapis.com/css2?family=Patrick+Hand&display=swap\" rel=\"stylesheet\"><style>html{font-family:'Patrick Hand',cursive;display:inline-block;margin:0px auto;text-align:center;background-color:#f0f8ff;color:#333;}h1{color:#4682b4;}ol{list-style-type:decimal;padding:0;margin:20px 0;}li{margin:10px 0;font-size:24px;transition:transform 0.3s ease,color 0.3s ease;transform-style:preserve-3d;}li:hover{transform:perspective(1000px) rotateX(10deg) scale(1.05);color:#4682b4;}.button{background-color:#1e90ff;border:none;color:white;padding:30px 70px;text-decoration:none;font-size:32px;cursor:pointer;border-radius:15px;transition:background-color 0.3s ease,transform 0.3s ease;display:block;width:90%;margin:0 auto;font-family:'Patrick Hand',cursive;transform-style:preserve-3d;}.button2{background-color:#555555;padding:24px 60px;font-size:28px;}.button:hover,.button2:hover{background-color:#4682b4;}</style></head><body><h1>ESP32 Alarm Music Player</h1>");
                        client.println(" <ol>");
 
                        for (i = 0; i < file_count; i++) {
                            if (i == curr_file) {
                                sprintf(req, "<li><a href=\"/%s/off\"><button class=\"button\">%s</button></a></li>", file_names[i], file_names[i]);
                            } else {
                                sprintf(req, "<li><a href=\"/%s/on\"><button class=\"button button2\">%s</button></a></li>", file_names[i], file_names[i]);
                            }
                            client.println(req);
                        }
 
                        client.println(" </ol>");
 
                        client.println("</body></html>");
 
                        client.println();
                        break;
                    } else {
                        current_line = "";
                    }
                } else if (c != '\r') {
                    current_line += c;
                }
 
            } else {
                play_note(current_note++);
                if (current_note >= current_size)
                    current_note = 0;
                update_distance();
            }
        }
        http_header = "";
        client.stop();
    }
 
    play_note(current_note++);
    if (current_note >= current_size)
        current_note = 0;
    update_distance();
}

Setup

Loop

File format

In this project, music files are stored on the SD card using a specific format. Each track is divided into two separate files: <trackname>.notes and <trackname>.durations. The .notes file contains the musical notes represented by 2 bytes each, while the .durations file stores the corresponding durations for each note, with each duration being one byte.

This file organization ensures efficient data management and retrieval during playback. The separation of notes and durations allows for flexibility in managing musical data. The system can easily access and interpret the musical notes and their durations independently, enabling seamless playback of various melodies and compositions.

The tracks were taken from hibit-dev's buzzer repository.

Web UI

This is where the user can select the tracks.

References

https://github.com/hibit-dev/buzzer

https://ocw.cs.pub.ro/courses/iothings/laboratoare/2022/lab3

https://randomnerdtutorials.com/esp32-microsd-card-arduino/

https://randomnerdtutorials.com/esp32-hc-sr04-ultrasonic-arduino/

https://randomnerdtutorials.com/esp32-web-server-arduino-ide/