Системам безопасности в современном мире с каждым годом уделяется все больше внимания. В последние годы все большую роль в системах безопасности начинают играть технологии интернета вещей (Internet of Things, IoT), которые могут автоматически запускать выполнение определенных событий: передача SMS в случае обнаружения тревоги, автоматический вызов полиции или пожарной бригады и т.д.
Ранее на нашем сайте мы рассмотрели достаточно много различных систем безопасности на основе плат Arduino и Raspberry Pi, в этой же статье мы рассмотрим создание умного Wi-Fi дверного звонка с камерой на основе модуля ESP32-CAM. Данный дверной звонок можно запитать от сети переменного тока и когда кто либо будет нажимать на кнопку этого звонка, то будет проигрываться определенная мелодия на вашем мобильном телефоне и вам будет передаваться текстовое сообщение со ссылкой на страницу, на которой вы на видео сможете посмотреть пришедшего посетителя.
Ранее на нашем сайте мы рассматривали использование модуля ESP32-CAM для видео трансляции и распознавания лиц.
Необходимые компоненты
- Модуль ESP32-CAM (купить на AliExpress).
- Плата FTDI для программирования модуля (купить на AliExpress).
- Преобразователь 220V AC в 5V DC.
- Зуммер (Buzzer) (купить на AliExpress).
- Кнопка.
- Светодиод – 2 шт. (купить на AliExpress).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Схема проекта
Схема умного дверного звонка с камерой на основе модуля ESP32-CAM представлена на следующем рисунке.
Как видите, схема достаточно проста. Зуммер используется для формирования звукового сигнала при нажатии кнопки звонка. Один светодиод используется для индикации подачи питания, а другой – для индикации статуса сети. Если модуль ESP32-CAM подключен к сети Wi-Fi, то данный светодиод будет гореть, иначе он будет мигать.
Автор проекта (ссылка на оригинал приведена в конце статьи) напечатал для данного дверного звонка корпус на 3D принтере, в результате у него получилась конструкция следующего вида:
Настройка сервиса IFTTT для умного Wi-Fi дверного замка
IFTTT представляет собой бесплатный в использовании сервис, который позволяет пользователям создавать простые цепочки действий с условиями, называемых "рецептами (recipes)", которые позволяют передавать сообщения в различные интернет сервисы, такие как Gmail, Facebook, Instagram, Pinterest и др. IFTTT расшифровывается как “If This Then That” (если произошло это, то выполнить то). На нашем сайте вы можете посмотреть все проекты с использованием сервиса IFTTT.
В нашем проекте мы будем использовать сервис IFTTT для передачи SMS на сотовый телефон.
Вначале заведите себе аккаунт на сервисе IFTTT (если у вас его еще нет). Затем в своем аккаунте в сервисе выполните поиск ‘Webhooks’ и затем выберите Webhooks в разделе Services.
Далее, в правом верхнем углу окна веб-хуков (Webhooks) нажмите на ссылку ‘Documentation’ чтобы получить приватный ключ (private key). Скопируйте себе этот ключ – в дальнейшем он нам понадобится в программе.
После получения приватного ключа мы создадим апплет (applet) используя веб-хуки и сервисы Email. Для создания апплета в сервисе IFTTT нажмите на иконку своего профиля и затем нажмите на пункт ‘Create.’
В следующем окне нажмите на иконку ‘This’.
Далее в секции поиска осуществите поиск Webhooks и затем нажмите на ‘Webhooks.’
После этого выберите триггер ‘Receive a Web Request’, в следующем окне введите имя события button_pressed (кнопка нажата) и затем нажмите create a trigger (создать триггер).
Затем, чтобы завершить создание апплета, нажмите на ‘That’ чтобы создать отклик на событие button_pressed.
Мы будем проигрывать определенную мелодию на сотовом телефоне когда кто-нибудь будет нажимать кнопку нашего дверного замка. Для этого в поле для поиска выполните поиск ‘Android device’.
В разделе Android Device выберите триггер ‘Play a specific song’ (проиграть определенную песню).
Затем введите название песни, которую вы хотите проигрывать при нажатии кнопки нашего дверного замка. В нашем случае мы будем проигрывать песню под именем ‘123’ из сервиса Google play music. Можно также использовать Spotify или другие музыкальные приложения.
После этого нажмите на ‘Create action’ (создать действие) и затем на ‘Finish’ чтобы завершить процесс.
Теперь создадим другой апплет – для передачи SMS со ссылкой на веб-страницу с видео трансляцией. Апплет будет также срабатывать при нажатии кнопки дверного замка.
Для создания данного апплета выберите ‘Webhooks’ в секции ‘this’ и затем в секции ‘that’ выберите ‘Android SMS’.
После этого сервис попросит вас ввести номер телефона и содержание сообщения. В нашем случае в сообщении мы будем передавать ссылку на веб-страницу с видео трансляцией с камеры звонка.
Объяснение программы для модуля ESP32
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Первым делом в коде программы подключим все необходимые библиотеки.
1 2 |
#include "esp_camera.h" #include <WiFi.h> |
Затем укажем параметры доступа к сети Wi-Fi – ее имя и пароль.
1 2 |
const char* ssid = "Wi-Fi Name"; const char* password = "Wi-Fi Password"; |
После этого введем имя хоста (hostname) сервиса IFTTT и приватный ключ, который мы ранее скопировали с этого сервиса.
1 2 |
const char *host = "maker.ifttt.com"; const char *privateKey = "Your Private Key"; |
Далее укажем все контакты, которые мы используем в проекте, для подключения кнопки, светодиода и зуммера.
1 2 3 |
const int buttonPin = 2; const int led1 = 14; const int buzzer = 15; |
Внутри функции void setup() зададим режимы работы используемых контактов – на ввод или вывод данных.
1 2 3 4 |
void setup() { pinMode(buttonPin, INPUT); pinMode(led1, OUTPUT); pinMode(buzzer, OUTPUT); |
Далее мы будем пытаться подключиться к сети Wi-Fi, когда нам это удастся, мы будем включать соответствующий светодиод (чтобы он горел постоянно). Пока мы не подключены к сети Wi-Fi светодиод будет мигать.
1 2 3 4 5 6 7 8 9 10 11 |
WiFi.begin(ssid, password); int led = LOW; while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); digitalWrite(led1, led); led = !led; } Serial.println(""); Serial.println("WiFi connected"); digitalWrite(led1, HIGH); |
Если соединение с сетью Wi-Fi будет потеряно, модуль ESP32 будет перезагружаться чтобы снова подключиться к сети.
1 2 3 4 |
while (WiFi.status() == WL_DISCONNECTED) { ESP.restart(); digitalWrite(led1, LOW); Serial.print("Connection Lost"); |
Модуль ESP32 будет считывать состояние кнопки и если ее состояние LOW (кнопка нажата), то модуль будет передавать событие "button_pressed" и включать зуммер на 3 секунды.
1 2 3 4 5 6 7 |
int reading = digitalRead(buttonPin); if (buttonState == LOW) { send_event("button_pressed"); Serial.print("button pressed"); digitalWrite(buzzer, HIGH); delay(3000); digitalWrite(buzzer, LOW); |
Печать корпуса для звонка на 3D принтере
Автор проекта напечатал корпус для нашего умного Wi-Fi дверного звонка на 3D принтере. Он измерил размеры модуля ESP32, кнопки, зуммера и светодиодов и на основе этих размеров спроектировал корпус для звонка, показанный на следующем рисунке.
Далее он конвертировал полученную модель корпуса звонка в STL файл, который вы можете скачать с Thingiverse и самостоятельно напечатать этот корпус на 3D принтере.
После окончательной сборки у него получилась следующая конструкция проекта.
Тестирование работы дверного звонка
После сборки аппаратной части проекта подключите звонок к сети переменного тока. После этого, когда кто-нибудь будет нажимать кнопку дверного замка, на смартфоне будет проигрываться мелодия под названием ‘123’ и на смартфон будет приходить сообщение со ссылкой на страницу с видео трансляцией как показано на следующем рисунке.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
#include "esp_camera.h" #include <WiFi.h> // // WARNING!!! Make sure that you have either selected ESP32 Wrover Module, // or another board which has PSRAM enabled // // Select camera model (выберите модель камеры) //#define CAMERA_MODEL_WROVER_KIT //#define CAMERA_MODEL_ESP_EYE //#define CAMERA_MODEL_M5STACK_PSRAM //#define CAMERA_MODEL_M5STACK_WIDE #define CAMERA_MODEL_AI_THINKER #include "camera_pins.h" void send_event(const char *event); const char* ssid = "Galaxy-M20"; const char* password = "ac312124"; const char *host = "maker.ifttt.com"; const char *privateKey = "hUAAAz0AVvc6-NW1UmqWXXv6VQWmpiGFxx3sV5rnaM9"; const int buttonPin = 2; int buttonState; // текущее состояние кнопки int lastButtonState = LOW; // предыдущее состояние кнопки const int led1 = 14; const int buzzer = 15; long lastDebounceTime = 0; // the last time the output pin was toggled long debounceDelay = 50; // the debounce time; increase if the output flickers (задержка для устранения дребезга контактов кнопки) void startCameraServer(); void setup() { pinMode(buttonPin, INPUT); pinMode(led1, OUTPUT); pinMode(buzzer, OUTPUT); Serial.begin(115200); Serial.setDebugOutput(true); Serial.println(); 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; //init with high specs to pre-allocate larger buffers if(psramFound()){ config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 10; config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; config.fb_count = 1; } #if defined(CAMERA_MODEL_ESP_EYE) pinMode(13, INPUT_PULLUP); pinMode(14, INPUT_PULLUP); #endif // camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } sensor_t * s = esp_camera_sensor_get(); //initial sensors are flipped vertically and colors are a bit saturated if (s->id.PID == OV3660_PID) { s->set_vflip(s, 1);//flip it back s->set_brightness(s, 1);//up the blightness just a bit (увеличиваем немного яркость) s->set_saturation(s, -2);//lower the saturation (уменьшаем немного насыщеность) } //drop down frame size for higher initial frame rate s->set_framesize(s, FRAMESIZE_QVGA); #if defined(CAMERA_MODEL_M5STACK_WIDE) s->set_vflip(s, 1); s->set_hmirror(s, 1); #endif WiFi.begin(ssid, password); int led = LOW; while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); digitalWrite(led1, led); led = !led; } Serial.println(""); Serial.println("WiFi connected"); digitalWrite(led1, HIGH); startCameraServer(); Serial.print("Camera Ready! Use 'http://"); Serial.print(WiFi.localIP()); Serial.println("' to connect"); } void loop() { while (WiFi.status() == WL_DISCONNECTED) { ESP.restart(); digitalWrite(led1, LOW); Serial.print("Connection Lost"); } int reading = digitalRead(buttonPin); if (reading != lastButtonState) { lastDebounceTime = millis(); } if ((millis() - lastDebounceTime) > debounceDelay) { // если состояние кнопки изменилось if (reading != buttonState) { Serial.print("Button now "); Serial.println(HIGH == reading ? "HIGH" : "LOW"); buttonState = reading; // When the button is in the LOW state (pulled high) the button has been pressed so send the event (кнопка нажата, передаем сообщение) if (buttonState == LOW) { send_event("button_pressed"); Serial.print("button pressed"); digitalWrite(buzzer, HIGH); delay(3000); digitalWrite(buzzer, LOW); } } } // сохраняем состояние кнопки lastButtonState = reading; } void send_event(const char *event) { Serial.print("Connecting to "); Serial.println(host); // Use WiFiClient class to create TCP connections WiFiClient client; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("Connection failed"); return; } // создаем URI для запроса String url = "/trigger/"; url += event; url += "/with/key/"; url += privateKey; Serial.print("Requesting URL: "); Serial.println(url); // передаем запрос на сервер client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); while(client.connected()) { if(client.available()) { String line = client.readStringUntil('\r'); Serial.print(line); } else { // No data yet, wait a bit (еще нет данных, немного ждем) delay(50); }; } Serial.println(); Serial.println("closing connection"); client.stop(); } |