Paso a paso del armado

Paso 1 Paso 2 Paso 3 Paso 4

Código

#include <Arduino.h>
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include <Wire.h>
#include <WiFiUdp.h>
#include "WifiCam.hpp"
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"

// Define the WiFi credentials
#define WIFI_SSID ""
#define WIFI_PASSWORD ""

// Define the Firebase project API Key
#define API_KEY "TU_API_KEY"

// Define RTDB URL
#define DATABASE_URL "https://mandar-notificacion-default-rtdb.firebaseio.com/"

// Define Firebase objects
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;

// Variable to save USER UID
String uid;

// Database main path (to be updated in setup with the user UID)
String databasePath;
String distancePath = "/distancia";  // Define the path to store distance data

// Parent Node (to be updated in every loop)
String parentPath;

esp32cam::Resolution initialResolution;

WebServer server(80);

// Sensor pins
const int triggerPin1 = 4;
const int echoPin1 = 2;
const int triggerPin2 = 14;
const int echoPin2 = 15;

const int umbral = 12;
const int distanciaMaxima = 200;

// Timer variables (send new readings every three minutes)
unsigned long sendDataPrevMillis = 0;
unsigned long timerDelay = 3000;  
bool signupOK = false;
int count = 0;

// Función para medir la distancia usando HC-SR04
float medirDistancia(int triggerPin, int echoPin) {
  // Establece el pin TRIGGER como salida
  pinMode(triggerPin, OUTPUT);
  digitalWrite(triggerPin, LOW);
  delayMicroseconds(2);

  // Genera un pulso corto en el pin TRIGGER
  digitalWrite(triggerPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggerPin, LOW);

  // Lee la duración del pulso en el pin ECHO
  pinMode(echoPin, INPUT);
  long duracion = pulseIn(echoPin, HIGH);

  // Calcula la distancia en centímetros (usando la velocidad del sonido en el aire)
  float distancia = (duracion / 2) * 0.0343;  // Dividido por 2 porque el pulso va de ida y vuelta

  return distancia;
}

void setup() {
  Serial.begin(115200);

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi failure");
    delay(5000);
    ESP.restart();
  }
  Serial.println("WiFi connected");

  {
    using namespace esp32cam;

    initialResolution = Resolution::find(1024, 768);

    Config cfg;
    cfg.setPins(pins::AiThinker);
    cfg.setResolution(initialResolution);
    cfg.setJpeg(80);

    bool ok = Camera.begin(cfg);
    if (!ok) {
      Serial.println("camera initialize failure");
      delay(5000);
      ESP.restart();
    }
    Serial.println("camera initialize success");
  }

  Serial.println("Conectado a WiFi");
  Serial.println(WiFi.localIP());

  // Inicializa la conexión WiFi
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Conectando a WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }

  /* Assign the api key (required) */
  config.api_key = API_KEY;

  /* Assign the RTDB URL (required) */
  config.database_url = DATABASE_URL;

  if (Firebase.signUp(&config, &auth, "", "")){
    Serial.println("ok");
    signupOK = true;
  }
  else{
    Serial.printf("%s\n", config.signer.signupError.message.c_str());
  }

  config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h

  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
  addRequestHandlers();
  server.begin();
}

void loop() {
  // Envía nuevas lecturas de distancia a la base de datos
  if (Firebase.ready() && signupOK && (millis() - sendDataPrevMillis > 5000 || sendDataPrevMillis == 0)){
    sendDataPrevMillis = millis();

    // Medir distancias con sensores HC-SR04
    float distancia1 = medirDistancia(triggerPin1, echoPin1);
    float distancia2 = medirDistancia(triggerPin2, echoPin2);

    // Comparar distancias y detectar objetos
    String estadoObjeto;
    if (distancia1 > distanciaMaxima && distancia2 > distanciaMaxima) {
      estadoObjeto = "Ningún objeto detectado";
    } else if (distancia1 - distancia2 > umbral) {
      estadoObjeto = "Objeto a la izquierda";
    } else if (distancia2 - distancia1 > umbral) {
      estadoObjeto = "Objeto a la derecha";
    } else {
      float distanciaPromedio = (distancia1 + distancia2) / 2;
      estadoObjeto = "Objeto en el medio a una distancia de " + String(distanciaPromedio) + " cm";
    }

    distancePath = "/detections/distancia";
    if (Firebase.RTDB.setString(&fbdo, distancePath, estadoObjeto.c_str())) {
      Serial.println("Dato enviado a Firebase: " + estadoObjeto);
    }

    server.handleClient();
  }
}
import cv2 #opencv
import urllib.request #para abrir y leer URL
import numpy as np
import firebase_admin 
from firebase_admin import credentials
from firebase_admin import db

#CONEXIÓN A LA BASE DE DATOS FIREBASE

# Configuración de las credenciales de Firebase 
firebase_cred = {
  "type": "service_account",
  "project_id": "mandar-notificacion",
  "private_key_id": "TU_PRIVATE_KEY_ID",
  "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
  "client_email": "firebase-adminsdk-royll@mandar-notificacion.iam.gserviceaccount.com",
  "client_id": "110485824900783183320",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-royll%40mandar-notificacion.iam.gserviceaccount.com",
  "universe_domain": "googleapis.com"
}

# Configura las credenciales de Firebase 
cred = credentials.Certificate(firebase_cred)

# Inicializa la base de datos de Firebase
firebase_admin.initialize_app(cred, {
    'databaseURL': 'https://mandar-notificacion-default-rtdb.firebaseio.com/'
})

firebase_db = db.reference()

#PROGRAMA DE CLASIFICACION DE OBJETOS PARA VIDEO EN DIRECCION IP 

url = 'http://192.168.2.115/800x600.jpg'

classNames = []
classFile = 'coco.names'
with open(classFile,'rt') as f:
    classNames = f.read().rstrip('\n').split('\n')

configPath = 'ssd_mobilenet_v3_large_coco_2020_01_14.pbtxt'
weightsPath = 'frozen_inference_graph.pb'

net = cv2.dnn_DetectionModel(weightsPath,configPath)
net.setInputSize(320,320)
net.setInputScale(1.0/127.5)
net.setInputMean((127.5, 127.5, 127.5))
net.setInputSwapRB(True)

while(1):
    imgResponse = urllib.request.urlopen (url) #abrimos el URL
    imgNp = np.array(bytearray(imgResponse.read()),dtype=np.uint8)
    img = cv2.imdecode (imgNp,-1) #decodificamos

    img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) # vertical

    classIds, confs, bbox = net.detect(img, confThreshold=0.5)

    if len(classIds) != 0:
        for classId, confidence, box in zip(classIds.flatten(), confs.flatten(), bbox):
            className = classNames[classId - 1]
            print(f'Objeto detectado: {className}')

            # Crear un diccionario con los datos de detección de objetos
            detection_data = {
                "object_name": className,
            }

            # Enviar los datos de detección de objetos a Firebase
            firebase_db.child('detections').set(detection_data)

    #esperamos a que se presione ESC para terminar el programa
    tecla = cv2.waitKey(5) & 0xFF
    if tecla == 27:
        break
cv2.destroyAllWindows()
firebase_admin.delete_app(firebase_admin.get_app())

Materiales

ESP-32 CAM

ESP-32 CAM

Arduino UNO R3

Arduino UNO R3

HC-SR 04

HC-SR 04