Camara con detector movimiento y bot de telegram




Presentación


El presente proyecto consiste en desarrollar un sistema de cámara que al detectar movimiento saque una foto y la envie a un bot de Telegram.

Tambien el bot de telegram se ha programado para que muestre el mensaje de inicio con la instrucción "/start", para que encienda y a pague el led con la instruccion "/flash" y con la instruccion "/photo" para que saque fotos

Para ello se utilizo la placa Esp32-Cam de Espressif, un sensor PIR para la deteción de movimiento y una bateria o fuente de 5 volts para la alimentación

Materiales


Placa Esp32-Cam

Sensor PIR

Batería


Circuito




Código


El codigo esta desarrolado en la IDE de arduino y se divide en cuatro archivos, el principal que he llamada camara.ino, el archivo camera_code.h que contiene la configuracion de la camara, el archivo camera_pins.h que contiene los pines de la camara, y el el archivo credencial.h que contiene las datos de la red wifi y del bot de telegram


camara.ino




	/*******************************************************************

   Un bot de Telegram para hacer una foto con una ESP32Cam

*******************************************************************/

// ----------------------------
// Librerias
// ----------------------------
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include "esp_camera.h"
#include <ArduinoJson.h>
#include "camera_pins.h"
#include "camera_code.h"
#include "credencial.h"



#define FLASH_LED_PIN 4

const unsigned long tiempo_escaneo = 1000; // tiempo medio entre mensajes escaneados

unsigned long ultimo_escaneo; // última vez que se realizó el escaneo de mensajes
WiFiClientSecure cliente;
UniversalTelegramBot bot(BOT_TOKEN, cliente);

const int pinSensor = 13; // PIR Motion Sensor



bool estado_flash = LOW;

camera_fb_t *fb = NULL;

bool hay_mas_datos();
byte *obtener_datos();
int largo_datos();

bool hay_datos = false;

int detec_mov = LOW;
int val = 0;


void enviar_foto(String id_chat ){

      fb = NULL;
      // Tomar foto con la cámara
      fb = esp_camera_fb_get();
      if (!fb)
      {
        Serial.println("Captura de cámara fallida");
        bot.sendMessage(id_chat, "Captura de cámara fallida", "");
        return;
      }
      hay_datos = true;
      Serial.println("Enviando");
      bot.sendPhotoByBinary(id_chat, "image/jpeg", fb->len,
                            hay_mas_datos, nullptr,
                            obtener_datos, largo_datos);

      Serial.println("hecho!");

      esp_camera_fb_return(fb);
  
}


void control_mov(){
  
    val = digitalRead(pinSensor);
        
      if (val == HIGH){
            if (detec_mov == LOW){
                  digitalWrite(FLASH_LED_PIN, HIGH);
                  Serial.println("Detecta Movimiento");
                  bot.sendMessage(id_autorizado, "Detecta Movimiento", "");
                  enviar_foto(id_autorizado);
                  detec_mov = HIGH;
                  delay(100),
                  digitalWrite(FLASH_LED_PIN, LOW);
            }
      }
      else{
            if (detec_mov == HIGH){
                  detec_mov = LOW;
            }
      }
}      

void manejo_mensajes(int num_mensaje)
{
  Serial.println("Nuevo mensaje");
  Serial.println(String(num_mensaje));

  for (int i = 0; i < num_mensaje; i++)
  {
    
    String chat_id = String(bot.messages[i].chat_id);
    
    if (chat_id != id_autorizado){
      bot.sendMessage(chat_id, "Usuario no autorizado", "");
      continue;
    }
    
    String text = bot.messages[i].text;

    String nombre = bot.messages[i].from_name;
    if (nombre == "")
      nombre = "Invitado";

    if (text == "/flash")
    {
      estado_flash = !estado_flash;
      digitalWrite(FLASH_LED_PIN, estado_flash);
    }

    if (text == "/photo")
    {
        enviar_foto(chat_id);
    }

    if (text == "/start")
    {
        String mensaj_bienvenida = "Bienvenido al bot de Telegram ESP32Cam.\n\n";
        mensaj_bienvenida += "/photo : tomará una foto\n";
        mensaj_bienvenida += "/flash : encender flash LED (¡MUY BRILLANTE!)\n";
        bot.sendMessage(chat_id, mensaj_bienvenida, "");
    }
    
  }
  
}

bool hay_mas_datos()
{
  
  if (hay_datos)
  {
    hay_datos = false;
    return true;
  }
  else
  {
    return false;
  }
}

byte *obtener_datos()
{
  if (fb)
  {
    return fb->buf;
  }
  else
  {
    return nullptr;
  }
}

int largo_datos()
{
  if (fb)
  {
    return fb->len;
  }
  else
  {
    return 0;
  }
}

void setup()
{
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  Serial.begin(115200);
  Serial.println();

  pinMode(FLASH_LED_PIN, OUTPUT);
  digitalWrite(FLASH_LED_PIN, estado_flash); //por defecto a bajo

  // PIR Motion Sensor mode INPUT_PULLUP
  pinMode(pinSensor, INPUT);
  // Set motionSensor pin as interrupt, assign interrupt function and set RISING mode
 // attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);





  if (!Config_Camara())
  {
    Serial.println("Configuración de la cámara fallida!");
    while (true)
    {
      delay(100);
    }
  }

  // intenta conectarte a la red wifi:
  Serial.print("Conexión a red Wi-Fi ");
  Serial.print(red);
  WiFi.begin(red, clave);
  cliente.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Agregar certificado raíz para api.telegram.org
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(500);
  }
  Serial.print("\nWi-Fi conectado. dirección IP: ");
  Serial.println(WiFi.localIP());

  Serial.print("Tiempo de recuperación: ");
  configTime(0, 0, "pool.ntp.org"); // obtener la hora UTC a través de NTP
  time_t now = time(nullptr);
  while (now < 24 * 3600)
  {
    Serial.print(".");
    delay(100);
    now = time(nullptr);
  }
  Serial.println(now);
  digitalWrite(FLASH_LED_PIN, HIGH);
  // Haz que el bot espere un nuevo mensaje hasta 60 segundos
  //bot.longPoll = 60;
  delay(5000);
  digitalWrite(FLASH_LED_PIN, LOW);
  bot.sendMessage(id_autorizado, "Bot iniciado", "");
}

void loop()
{
  if (millis() - ultimo_escaneo > tiempo_escaneo)

  {
    
    int num_mensaje = bot.getUpdates(bot.last_message_received + 1);

    while (num_mensaje)
    {
      
      Serial.println("obtuve respuesta");
      manejo_mensajes(num_mensaje);
      
      //investigar tiempo y funcionamiento de bot.getUpdates 
      num_mensaje = bot.getUpdates(bot.last_message_received + 1);
      
    }

    ultimo_escaneo = millis();


  }

  control_mov();
 


}  

camera_code.h




	bool Config_Camara()
{
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  //iniciar con altas especificaciones para preasignar búferes más grandes
  if (psramFound())
  {
    config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
    config.jpeg_quality = 10;
    config.fb_count = 2;
  }
  else
  {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }


  // iniciar camara
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK)
  {
    Serial.printf("El inicio de la cámara falló con un error 0x%x", err);
    return false;
  }

  sensor_t *s = esp_camera_sensor_get();
  //los sensores iniciales están volteados verticalmente y los colores están un poco saturados
  if (s->id.PID == OV3660_PID)
  {
    s->set_vflip(s, 1);       //darle la vuelta
    s->set_brightness(s, 1);  //Sube el brillo un poco
    s->set_saturation(s, -2); //bajar la saturación
  }
  //tamaño de fotograma desplegable para una velocidad de fotogramas inicial más alta
  s->set_framesize(s, FRAMESIZE_QVGA);


  return true;
}



camera_pins.h




	
//CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27

#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22


credencial.h




	//Credenciales de red
	const char* red = "xxxxxxxxxxx";
	
	const char* clave = "xxxxxxxxxxxxxx";
	
	
	// Token BOT de Telegram (Obtener de Botfather)
	#define BOT_TOKEN "xxxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
	
	
	// Usa @myidbot para averiguar el ID de chat de un individuo o un grupo
	// También tenga en cuenta que debe hacer clic en "iniciar" en un bot antes de que pueda enviar mensajes
	String id_autorizado = "xxxxxxxxxxxxxx";	


Cerrar