ESP32 Customizable Parking Sensor

  • Author: Sergiu Moga
  • Email: sergiu.moga@protonmail.com
  • Master: SAS

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

  • SDCard stores music files
  • Distance sensor reports obstacle proximity
  • Buzzer outputs the music
  • Buzzer frequency increases as obstacle gets closer
  • Web interface allows user to choose the melody
  • Web interface shows distance to obstacle

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

  • Begin Serial Communication: Initializes the serial communication for debugging.
  • Mount SD Card: Attempts to mount the SD card. If successful, it checks if the root directory exists and is accessible.
  • Retrieve File Information: Iterates through each file in the root directory, reads the duration, melody, and name of each file, and stores them in respective arrays.
  • Initialize Pins: Sets the pinMode for the buzzer, trigger, and echo pins.
  • Connect to WiFi: Attempts to connect to the specified WiFi network.
  • Start Web Server: Begins hosting a web server on port 80.
  • Sets the initial melody, duration, and size to the first music file.

Loop

  • Check for Client Connection: Listens for incoming client connections on the web server.
  • Handle Client Requests: If a client connects, the code checks for available data from the client.
  • Parse HTTP Request: Reads the HTTP request and extracts the requested file name.
  • Find Matching File: Searches for the requested file name in the list of available music files.
  • Generate HTML Response: Constructs an HTML response containing buttons for each music file, highlighting the currently selected file.
  • Respond to Client: Sends the HTML response to the client.
  • Handle Note Playback and Distance Update: While waiting for client requests or after responding to a request, the code continuously plays notes from the selected melody and updates the distance reading from the sensor. The playback speed of the melody is adjusted based on the proximity of obstacles detected by the distance sensor.

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

iothings/proiecte/2023sric/customizablealarmsystem.txt · Last modified: 2024/05/30 00:07 by sergiu.moga
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0