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";