Skip to content

Commit

Permalink
Update ESP32-CAM-PIR.ino
Browse files Browse the repository at this point in the history
  • Loading branch information
cotestatnt committed Apr 14, 2024
1 parent f9c9691 commit 749a82e
Showing 1 changed file with 167 additions and 104 deletions.
271 changes: 167 additions & 104 deletions examples/ESP32/ESP32-CAM-PIR/ESP32-CAM-PIR.ino
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
Name: ESP32-CAM-PIR.ino
Created: 11/04/2024
Author: Tolentino Cotesta <[email protected]>
Description:
In this example, the Telegram bot management code runs in a FreeRTOS task.
When a PIR sensor is excited, a sequence of NUM_PHOTO images will be sent taking every DELAY_PHOTO ms
*/

#include <WiFi.h>
#include <FS.h>
#include <AsyncTelegram2.h>
Expand All @@ -8,9 +17,15 @@
// Local include files
#include "camera_pins.h"

#define USE_MMC true // Define where store images (on board SD card reader or internal flash memory)
#define PIR_PIN GPIO_NUM_14
#define NUM_PHOTO 3 // Total number of photos to send on motion detection
#define DELAY_PHOTO 5000 // Waiting time between one photo and the next
#define DELAY_FLASH 500 // Flash delay time

#define STORE_IMAGE false // Save the pictures also in SDmmemory card
#define USE_MMC true // Define where store images (on board SD card reader or internal flash memory)
#if USE_MMC
#include <SD_MMC.h> // Use onboard SD Card reader
#include <SD_MMC.h> // Use onboard SD Card reader
#define FILESYSTEM SD_MMC
#else
#include <FFat.h> // Use internal flash memory
Expand All @@ -20,45 +35,78 @@
#include <WiFiClientSecure.h>
WiFiClientSecure client;

#define PIR_PIN GPIO_NUM_13

const char* ssid = "xxxxxxxxx"; // SSID WiFi network
const char* pass = "xxxxxxxxx"; // Password WiFi network
const char* token = "xxxxxxxxxx:xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx"; // Telegram token
// Check the userid with the help of bot @JsonDumpBot or @getidsbot (work also with groups)
// https://t.me/JsonDumpBot or https://t.me/getidsbot
int64_t userid = 123456789;

const char* ssid = "XXXXXX"; // SSID WiFi network
const char* pass = "XXXXXX"; // Password WiFi network
const char* token = "XXXX:XXXXXXX-XXXXXXX-XXXXXX"; // Telegram token

#define PIR_PIN GPIO_NUM_13
#define NUM_PHOTO 3 // Total number of photos to send on motion detection
#define DELAY_PHOTO 2000 // Waiting time between one photo and the next
// Target user can find it's own userid with the bot @JsonDumpBot
// https://t.me/JsonDumpBot
int64_t userid = 1234567890;

int currentPict = 3;
bool captureEnabled = false;
int currentPict = NUM_PHOTO;
AsyncTelegram2 myBot(client);

// Timezone definition to get properly time from NTP server
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"

// Struct for saving time datas (needed for time-naming the image files)
struct tm tInfo;
struct tm tInfo, bootTime;

// Functions prototype
// Declare functions prototype here, so we can leave the
// definitions at the bottom of the sketch without worries
void listDir(const char *, uint8_t, bool) ;
void printHeapStats();
static void checkTelegram(void *);
void setLamp(int);
size_t sendPicture(bool, int64_t);
void parseTelegramMessage( const TBMessage &msg);

// Help message
const char* help_msg PROGMEM =
"Welcome to the ESP32-CAM BirdCam Telegram bot.\n"
"/start: Start detection\n"
"/stop: Stop detection\n"
"/reboot : Reboot Birdcam\n"
"/photo: Takes a new photo\n"
"/flash: Toggle flash LED\n"
"/boot: Boot time ESP32-CAM\n"
#if STORE_IMAGE
"/list: List all stored pictures\n"
"/deleteAll: Delete all pictures\n"
#endif
"To start capture pls run the /start command\n"
"You'll receive a photo whenever motion is detected.\n";

// This is the task for checking new messages from Telegram
static void checkTelegram(void * args) {
while (true) {
// A variable to store telegram message data
TBMessage msg;
// if there is an incoming message...
if (myBot.getNewMessage(msg)) {
Serial.print("New message from chat_id: ");
Serial.println(msg.chatId);

// Received a text message
if ( msg.messageType == MessageText) {
parseTelegramMessage(msg);
}
}
yield();
}
// Delete this task on exit (should never occurs)
vTaskDelete(NULL);
}


/////////////////////////////////// SETUP ///////////////////////////////////////
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable brownout detect
Serial.begin(115200);
Serial.println();

WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable brownout detect

// PIR Motion Sensor setup
pinMode(PIR_PIN, INPUT_PULLUP);
pinMode(PIR_PIN, INPUT);

// Flash LED setup
pinMode(LAMP_PIN, OUTPUT); // set the lamp pin as output
Expand Down Expand Up @@ -104,7 +152,7 @@ void setup() {

// Send a welcome message to user when ready
char welcome_msg[128];
snprintf(welcome_msg, 128, "BOT @%s online.\nTry with /takePhoto or /savePhoto", myBot.getBotName());
snprintf(welcome_msg, 128, "BOT @%s online.\nWrite /help for commands list", myBot.getBotName());
myBot.sendTo(userid, welcome_msg);

// Start telegram message check task
Expand All @@ -126,93 +174,110 @@ void setup() {
/////////////////////////////////// LOOP ///////////////////////////////////////
void loop() {
// printHeapStats();

// PIR motion detected, start picture acquisition
static uint32_t waitPhotoTime;
if(digitalRead(PIR_PIN) == HIGH && captureEnabled) {
currentPict = 0;
waitPhotoTime = 0;
char message[50];
time_t now = time(nullptr);
tInfo = *localtime(&now);
strftime(message, sizeof(message), "%d/%m/%Y %H:%M:%S - Motion detected!", &tInfo);
Serial.println(message);
myBot.sendTo(userid, message);
}

// Non blocking delay time and check amount of pictures sent
if (millis() - waitPhotoTime > DELAY_PHOTO && currentPict < NUM_PHOTO) {
waitPhotoTime = millis();
size_t bytes_sent = sendPicture(true, userid);
if (bytes_sent) {
Serial.printf("CAM picture sent to Telegram (%d bytes)\n", bytes_sent);
currentPict++;
}
}
}


////////////////////////////////// FUNCTIONS//////////////////////////////////////

// This is the task for checking new messages from Telegram
static void checkTelegram(void * args) {
while (true) {
static uint32_t waitPhotoTime;
void parseTelegramMessage( const TBMessage &msg){
// Send a picture grabbed from camera directly to Telegram
if (msg.text.equalsIgnoreCase("/photo")) {
uint32_t t1 = millis();
size_t bytes_sent = sendPicture(false, msg.chatId);
if (bytes_sent)
Serial.printf("Picture sent to Telegram (%d bytes)\n", bytes_sent);

// PIR motion detected
// could be on interrupt, but PIR sensor usually keep signal HIGH for enough time
if(digitalRead(PIR_PIN) == LOW) {
currentPict = 0;
waitPhotoTime = 0;
char message[50];
time_t now = time(nullptr);
tInfo = *localtime(&now);
strftime(message, 50, "%d/%m/%Y %H:%M:%S - Motion detected!", &tInfo);
Serial.println(message);
myBot.sendTo(userid, message);
}

if(millis() - waitPhotoTime > DELAY_PHOTO && currentPict < NUM_PHOTO) {
waitPhotoTime = millis();
size_t bytes_sent = sendPicture(true, userid);
if (bytes_sent) {
Serial.printf("CAM picture sent to Telegram (%d bytes)\n", bytes_sent);
currentPict++;
}
}
Serial.printf("Total upload time (server latency time included, ~ 500 ms): %lu ms\n", millis() - t1 );
}

// A variable to store telegram message data
TBMessage msg;
// if there is an incoming message...
if (myBot.getNewMessage(msg)) {
Serial.print("New message from chat_id: ");
Serial.println(msg.chatId);
MessageType msgType = msg.messageType;
// Start motion capture
else if (msg.text.equalsIgnoreCase("/start")) {
captureEnabled = true;
myBot.sendMessage(msg, "Motion capture enabled");
}

// Received a text message
if (msgType == MessageText) {

// Send a picture grabbed from camera directly to Telegram
if (msg.text.equalsIgnoreCase("/takePhoto")) {
uint32_t t1 = millis();
size_t bytes_sent = sendPicture(false, msg.chatId);
if (bytes_sent) Serial.printf("Picture sent to Telegram (%d bytes)\n", bytes_sent);

Serial.printf("Total upload time (server latency time included, ~ 500 ms): %lu ms\n", millis() - t1 );
}

// Save a picture and then send to Telegram
else if (msg.text.equalsIgnoreCase("/savePhoto")) {
size_t bytes_sent = sendPicture(true, msg.chatId);
if (bytes_sent) Serial.printf("Picture saved and sent to Telegram (%d bytes)\n", bytes_sent);
}

// Delete all files in folder
else if (msg.text.equalsIgnoreCase("/deleteAll")) {
listDir("/", 0, true);
myBot.sendMessage(msg, "All files deleted.");
}

// Delete all files in folder
else if (msg.text.equalsIgnoreCase("/listDir")) {
listDir("/", 0, false);
myBot.sendMessage(msg, "All files listed on Serial port.");
}

// Echo received message and send command list
else {
Serial.print("\nText message received: ");
Serial.println(msg.text);
String replyStr = "Message received:\n";
replyStr += msg.text;
replyStr += "\nTry with /takePhoto or /savePhoto";
myBot.sendMessage(msg, replyStr);
}
}
// Stop motion capture
else if (msg.text.equalsIgnoreCase("/stop")) {
captureEnabled = false;
myBot.sendMessage(msg, "Motion capture disabled");
}

// Send ESP32 runtime (HH:MM:SS)
else if (msg.text.equalsIgnoreCase("/boot")) {
time_t rawTime = millis() / 1000;
struct tm *timeInfo = gmtime(&rawTime);
char timeStr[32];
strftime(timeStr, sizeof(timeStr), "ESP32-CAM run since: %H:%M:%S", timeInfo);
Serial.println(timeStr);
myBot.sendMessage(msg, timeStr);
}

// Send /help menu list
else if (msg.text.equalsIgnoreCase("/help")) {
myBot.sendMessage(msg, help_msg);
}

// Reboot ESP
else if (msg.text.equalsIgnoreCase("/reboot")) {
myBot.sendMessage(msg, "Restarting in few seconds...");
// Avoid bootloop
while (!myBot.noNewMessage()) {
Serial.print(".");
delay(50);
}
yield();
ESP.restart();
}

#if STORE_IMAGE
// Delete all files in folder
else if (msg.text.equalsIgnoreCase("/deleteAll")) {
listDir("/", 0, true);
myBot.sendMessage(msg, "All files deleted.");
}

// Delete all files in folder
else if (msg.text.equalsIgnoreCase("/list")) {
listDir("/", 0, false);
myBot.sendMessage(msg, "All files listed on Serial port.");
}
#endif

// Echo received message and send command list
else {
Serial.print("\nText message received: ");
Serial.println(msg.text);
String replyStr = "Message received:\n";
replyStr += msg.text;
replyStr += "\nCommands list with /help";
myBot.sendMessage(msg, replyStr);
}
// Delete this task on exit (should never occurs)
vTaskDelete(NULL);
}




// Lamp Control
void setLamp(int newVal) {
if (newVal != -1) {
Expand All @@ -233,6 +298,7 @@ size_t sendPicture(bool saveImg, int64_t chatId) {

// Take Picture with Camera and store in ram buffer fb
setLamp(100);
delay(DELAY_FLASH);
camera_fb_t* fb = esp_camera_fb_get();
setLamp(0);
if (!fb) {
Expand All @@ -242,7 +308,7 @@ size_t sendPicture(bool saveImg, int64_t chatId) {
size_t len = fb->len;

// If is necessary keep the image file, save and send as stream object
if (saveImg) {
#if STORE_IMAGE
// Keep files on SD memory, filename is time based (YYYYMMDD_HHMMSS.jpg)
#if USE_MMC
char filename[30];
Expand All @@ -263,12 +329,9 @@ size_t sendPicture(bool saveImg, int64_t chatId) {
file.close();
Serial.printf("Saved file to path: %s - %zu bytes\n", filename, fb->len);
myBot.sendPhoto(chatId, filename, FILESYSTEM);
}

// If is NOT necessary keep the image file, send picture directly from ram buffer
else {
#else
myBot.sendPhoto(chatId, fb->buf, fb->len);
}
#endif

// Clear buffer
esp_camera_fb_return(fb);
Expand Down

0 comments on commit 749a82e

Please sign in to comment.