Всем привет! Сегодня мы разберем как сделать систему видеонаблюдения на базе esp32-cam и Telegram.
Используя популярный мессенджер Telegram, можно не задумываться о наличии "белого" Ip адреса, для выхода в сеть. Для реализации проекта посмотрим на схему:

Когда мы отправляем боту команду, он через сервера telegram-а пересылает её на esp, которая с периодичностью раз в секунду опрашивает сервер.
После получения запроса на отправку фото, esp делает снимок, загружает его на сайт telegram-а, а уже сам telegram через бот посылает её нам.
Сделаем мини камеру мобильной, чтобы можно было удобно расположить её:

Производить зарядку удобнее всего модулем TP4056, который поддерживает защиту аккумуляторов и отлично подойдет для 18650.
При потреблении esp32 около 260 мА⋅ч, батареи на 5800 mA⋅ч хватит на сутки постоянной передачи.

Я Приклеил модуль tp на esp через двухсторонний скотч, провода от tp OUT+, OUT- подключаем к 5V и GND. А B+, B- к аккумулятору.
Перейдем к созданию бота, для этого отправляемся к @BotFather и отправляем ему команду: /newbot

Далее придумываем название боту:

Последний шаг это username бота — уникальный ник, по которому легко найти и поделится ботом (должен оканчиваться на bot):

Все! Бот успешно создан, копируем его токен, он нам дальше понадобиться:
5853076693:AAGelU8TwAeu6TRtIQbtr97noqHWi1-ORvY
Чтобы запретить другим людям пользоваться ботом, узнаем собственный user_id. Переходим в @myidbot и отправляем команду /getid:

Напишем скетч:
Для работы с TelegramBotApi будем использовать библиотеку UniversalTelegramBot. А для подключения к wifi, менеджер ESPConnect.
Подключаем библиотеки:
#include <Arduino.h> #include <WiFi.h> #include <AsyncTCP.h> #include <WiFiClientSecure.h> #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "esp_camera.h" #include <UniversalTelegramBot.h> #include <ArduinoJson.h> #include <ESPConnect.h> #include <ESPAsyncWebServer.h>
Измените настройки под свои:
String BOTtoken = "ТОКЕН-БОТА"; String CHAT_ID = "ВАШ-USERID"; int botRequestDelay = 1000; //задержка для проверки новых сообщений
Инициализируем объекты:
AsyncWebServer server(80); WiFiClientSecure clientTCP; UniversalTelegramBot bot(BOTtoken, clientTCP); bool sendPhoto = false; bool flashState = LOW; unsigned long lastTimeBotRan; #define FLASH_LED_PIN 4
Начальная настройка:
void setup(){
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200); //Монитор порта
pinMode(FLASH_LED_PIN, OUTPUT);
digitalWrite(FLASH_LED_PIN, flashState);
configInitCamera();
WiFi.mode(WIFI_STA);
// WiFi.begin(ssid, password);
ESPConnect.autoConnect("Название точки доступа для менеджера"); //Подключение к wifi
clientTCP.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Сертификат для api.telegram.org
while (!ESPConnect.begin(&server)) {
Serial.print(".");
delay(500);
}
Serial.println();
Serial.print("ESP32-CAM IP Address: ");
Serial.println(WiFi.localIP());
}
Главная программа (Если стоит флаг sendPhoto то делаем и отправляем фото):
void loop() {
if (sendPhoto) {
Serial.println("Готовим фото");
sendPhotoTelegram();
sendPhoto = false;
}
if (millis() > lastTimeBotRan + botRequestDelay) {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
Serial.println("Ответ получен!");
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
lastTimeBotRan = millis();
}
}
Функция конфигурации камеры (объявляем все пины камеры и инициализируем камеру):
void configInitCamera(){
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = 5;
config.pin_d1 = 18;
config.pin_d2 = 19;
config.pin_d3 = 21;
config.pin_d4 = 36;
config.pin_d5 = 39;
config.pin_d6 = 34;
config.pin_d7 = 35;
config.pin_xclk = 0;
config.pin_pclk = 22;
config.pin_vsync = 25;
config.pin_href = 23;
config.pin_sscb_sda = 26;
config.pin_sscb_scl = 27;
config.pin_pwdn = 32;
config.pin_reset = -1;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
}
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Инициализация камеры завершилась с ошибкой: 0x%x", err);
delay(1000);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_XGA); // Доступные разрешения камеры: UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
}
В строчке: s->set_framesize(s, FRAMESIZE_XGA); можно указать качество фото, начиная от QQVGA и заканчивая UXGA. На практике лучше всего отправляются фотографии качества XGA и ниже.
Функция отвечающая за прием и обработку новых сообщений:
void handleNewMessages(int numNewMessages) {
Serial.print("Ожидаем новые сообщения: ");
Serial.println(numNewMessages);
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
if (chat_id != CHAT_ID){
bot.sendMessage(chat_id, "Неавторизованный пользователь", "");
continue;
}
String text = bot.messages[i].text;
Serial.println(text); //присланное сообщение
String from_name = bot.messages[i].from_name;
//Меню: (Тут можно добавить свои команды)
if (text == "/start") {
String welcome = "Привет , " + from_name + "!\n";
welcome += "Доступные команды:\n";
welcome += "/photo : сделать фото\n";
welcome += "/flash : включить светодиод\n";
bot.sendMessage(CHAT_ID, welcome, "");
}
if (text == "/flash") {
flashState = !flashState;
digitalWrite(FLASH_LED_PIN, flashState);
Serial.println("Изменяем состояние светодиода");
}
if (text == "/photo") {
sendPhoto = true;
Serial.println("Новый запрос на фотографию");
}
}
}
Функция создания снимка и отправки на сервер:
String sendPhotoTelegram() {
const char* myDomain = "api.telegram.org";
String getAll = "";
String getBody = "";
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Ошибка камеры");
delay(1000);
ESP.restart();
return "Ошибка камеры";
}
Serial.println("Подключаемя к " + String(myDomain));
if (clientTCP.connect(myDomain, 443)) {
Serial.println("Успешное подключение");
String head = "--Amperkot\r\nContent-Disposition: form-data; name=\"chat_id\"; \r\n\r\n" + CHAT_ID + "\r\n--Amperkot\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--Amperkot--\r\n";
uint16_t imageLen = fb->len;
uint16_t extraLen = head.length() + tail.length();
uint16_t totalLen = imageLen + extraLen;
clientTCP.println("POST /bot"+BOTtoken+"/sendPhoto HTTP/1.1");
clientTCP.println("Host: " + String(myDomain));
clientTCP.println("Content-Length: " + String(totalLen));
clientTCP.println("Content-Type: multipart/form-data; boundary=Amperkot");
clientTCP.println();
clientTCP.print(head);
uint8_t *fbBuf = fb->buf;
size_t fbLen = fb->len;
for (size_t n=0;n<fbLen;n=n+1024) {
if (n+1024<fbLen) {
clientTCP.write(fbBuf, 1024);
fbBuf += 1024;
}
else if (fbLen%1024>0) {
size_t remainder = fbLen%1024;
clientTCP.write(fbBuf, remainder);
}
}
clientTCP.print(tail);
esp_camera_fb_return(fb);
int waitTime = 10000;
long startTimer = millis();
boolean state = false;
while ((startTimer + waitTime) > millis()){
Serial.print(".");
delay(100);
while (clientTCP.available()) {
char c = clientTCP.read();
if (state==true) getBody += String(c);
if (c == '\n') {
if (getAll.length()==0) state=true;
getAll = "";
}
else if (c != '\r')
getAll += String(c);
startTimer = millis();
}
if (getBody.length()>0) break;
}
clientTCP.stop();
Serial.println(getBody);
}
else {
getBody="Не удалось подключиться к api.telegram.org.";
Serial.println("Не удалось подключиться к api.telegram.org.");
}
return getBody;
}
Т. к. esp32-cam не имеет встроенного UART-USB входа, то необходим uart-переходник. Подключаем по схеме:
Красный - 5V Черный - GND Зеленый - U0R Белый - U0T
Перед загрузкой обязательно соедините IOO с gnd. (после загрузки разъединить)
Загружаем... после проверяем wifi сети, там должна появиться точка доступа с вашим названием:

Подключаемся и выбираем свою домашнюю сеть. Вводим логин и пароль. Это удобно когда вы не знаете где придется разместить камеру.
После подключения отправляем нашему боту команду /start:

Испробуем /flash:
Отлично, теперь /photo:

Качество очень хорошее (но авто-фокуса нет):

Фотография приходит через пару секунд после отправки команды, это нормально. ESP требуется время, чтобы загрузить и обработать снимок.
Если мы попробуем зайти с другого аккаунта, то получим сообщение: Пользователь не авторизирован
На этом сегодня все! Камеру можно поставить над 3d принтером и следить за прогрессом печати из любой точки мира. Или в дверной глазок. Спасибо за внимание и удачи в ваших проектах!
Данная статья является собственностью Amperkot.ru. При перепечатке данного материала активная ссылка на первоисточник, не закрытая для индексации поисковыми системами, обязательна.
Комментарии