#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include "DHTesp.h"
#include <ESP32Servo.h>
#include <Keypad.h>
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""
#define BOT_TOKEN "7978061436:AAHKc3d100Lg4JBkv4QjUOQZjXMMibXebAs"
#define BOT_MTBS 1000
#define PIR 13
#define LDR_PIN 34
#define chsen4 35
#define ECHO_PIN 14
#define TRIG_PIN 12
#define SPEAKER_PIN 23
#define DHT_PIN 22
#define pinG 26
#define pinR 27
#define pinB 25
const int servoPin = 32;
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','H'},
{'4','5','6','T'},
{'7','8','9','O'},
{'Del','0','=','!'}
};
byte rowPins[ROWS] = {19, 21, 17, 16};
byte colPins[COLS] = {15, 2, 0, 4};
String passwordlog = "HTO!";
String password;
bool alarmActive = true;
bool distanceTriggered = false;
bool pirTriggered = false;
bool flagPIR = false;
bool CH4 = false;
bool light;
bool last_CH4_state = false;
bool servoST;
bool lightST;
bool lastLightState = false;
bool manualMode = false;
bool buzzerState = false;
bool Serialpasswordflag = false;
bool passwordflagtrue = false;
bool passwordflagfalse = false;
bool timerActive = false;
bool gas_alert_sent = false;
// Сохраняем последний установленный цвет
int lastRed = HIGH;
int lastGreen = HIGH;
int lastBlue = LOW;
int val = 0;
int distance;
int t, h;
unsigned long passwordTimerStart = 0;
unsigned long bot_lasttime;
unsigned long last_gas_alert = 0;
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
Servo servo;
DHTesp dhtSensor;
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);
String keyboardMain = "[[\"Доклад\", \"Периферия\"]]";
String keyboardPeriphery = "[[\"Ручной режим\", \"Авто режим\"], [\"Свет ВКЛ\", \"Свет ВЫКЛ\"], [\"Цвет света\", \"Окно\"], [\"Пищалка ВКЛ\", \"Пищалка ВЫКЛ\"], [\"Сигнализация ВКЛ\", \"Сигнализация ВЫКЛ\"], [\"Назад\"]]";
String keyboardColors = "[[\"Красный\", \"Зеленый\", \"Синий\"], [\"Желтый\", \"Фиолетовый\", \"Белый\"], [\"Периферия\"]]";
String keyboardWindow = "[[\"Открыть окно\", \"Закрыть окно\"], [\"Периферия\"]]";
String chat_id = "";
void setLEDColor(bool red, bool green, bool blue) {
digitalWrite(pinR, red);
digitalWrite(pinG, green);
digitalWrite(pinB, blue);
// Сохраняем последний установленный цвет
lastRed = red;
lastGreen = green;
lastBlue = blue;
}
void applySavedColor() {
digitalWrite(pinR, lastRed);
digitalWrite(pinG, lastGreen);
digitalWrite(pinB, lastBlue);
}
String getWeatherDescription(int temperature, int humidity) {
if (temperature >= 15 && temperature <= 25 && humidity >= 40 && humidity <= 70) {
return "🌤Температура и влажность в комфортном диапазоне. Идеальный день для прогулок.🌤";
}
else if (temperature < 15 && humidity < 40) {
return "❄️Низкая температура сочетается с низкой влажностью. Оденьтесь теплее, пейте воду для увлажнения изнутри.❄️";
}
else if (temperature > 25 && humidity < 40) {
return "🔥Высокая температура и сухой воздух. Высок риск перегрева. Пейте много воды, носите головной убор.🔥";
}
else if (temperature < 15 && humidity > 70) {
return "💨Влажно и прохладно. Одевайтесь теплее, отдавайте предпочтение непромокаемой и ветрозащитной одежде.💨";
}
else if (temperature > 25 && humidity > 70) {
return "💦Высокая температура и высокая влажность. Нагрузка на организм максимальна. Ограничьте активность, пейте больше воды.💦";
}
else if (humidity >= 40 && humidity <= 70 && (temperature < 10 || temperature > 30)) {
return "⚠️Влажность комфортная, но температура экстремально низкая/высокая. Главный риск — сильный мороз/палящее солнце. Одевайтесь по погоде крайне тщательно.⚠️";
}
else {
return "📊Умеренные условия. Температура и влажность в приемлемых пределах.📊";
}
}
int readDistanceCM() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
int duration = pulseIn(ECHO_PIN, HIGH);
return duration * 0.034 / 2;
}
void handleNewMessages(int numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
chat_id = bot.messages[i].chat_id;
String text = bot.messages[i].text;
String nn = "\n";
String from_name = bot.messages[i].from_name;
if (from_name == "") from_name = "Guest";
if(text == "Доклад"){
String weatherInfo = getWeatherDescription(t, h);
String dokl = "🗂Параметры🗂:" + nn;
dokl += "🌡Температура🌡: " + String(t) + "℃" + nn;
dokl += "💧Влажность💧: " + String(h) + "%" + nn;
dokl += "📡Ультразвук📡: " + String(distance) + " см" + nn;
dokl += "☁️Датчик газа☁️: " + String(CH4 ? "🔴Внимание газ🔴" : "🟢Чисто🟢") + nn;
dokl += "💡Датчик света💡: " + String(light ? "🌚Темно🌚" : "☀️Светло☀️") + nn;
dokl += "🏃➡️PIR датчик🏃➡️: " + String(flagPIR ? "🔴Движение🔴" : "🟢Чисто🟢") + nn;
dokl += nn;
dokl += "📡Периферия📡:" + nn;
dokl += "🚨Сигнализация🚨: " + String(alarmActive ? "🔴АКТИВНА🔴" : "🟢ВЫКЛ🟢") + nn;
dokl += "🪟Серво (окно)🪟: " + String(servoST ? "🟢Открыто🟢" : "🔴Закрыто🔴") + nn;
dokl += "💡Светодиод💡: " + String(lightST ? "🟢Включен🟢" : "🔴Выключен🔴") + nn;
dokl += "🔊Пищалка🔊: " + String(buzzerState ? "🟢Включена🟢" : "🔴Выключена🔴") + nn;
dokl += "👨💼Режим👨💼: " + String(manualMode ? "🟢Ручной🟢" : "🔴Авто🔴") + nn;
dokl += nn;
dokl += "📈Анализ погоды📈:" + nn;
dokl += weatherInfo;
bot.sendMessageWithReplyKeyboard(chat_id, dokl, "", keyboardMain, true);
}
else if(text == "Периферия"){
String peri = "🛠Управление периферией🛠:" + nn;
peri += "💡Свет💡: " + String(lightST ? "🟢ВКЛ🟢" : "🔴ВЫКЛ🔴") + nn;
peri += "🪟Окно🪟: " + String(servoST ? "🟢Открыто🟢" : "🔴Закрыто🔴") + nn;
peri += "🔊Пищалка🔊: " + String(buzzerState ? "🟢ВКЛ🟢" : "🔴ВЫКЛ🔴") + nn;
peri += "🚨Сигнализация🚨: " + String(alarmActive ? "🟢ВКЛ🟢" : "🔴ВЫКЛ🔴") + nn;
peri += "👨💼Режим👨💼: " + String(manualMode ? "🟢Ручной🟢" : "🔴Авто🔴") + nn;
bot.sendMessageWithReplyKeyboard(chat_id, peri, "", keyboardPeriphery, true);
}
else if(text == "Ручной режим"){
manualMode = true;
bot.sendMessageWithReplyKeyboard(chat_id, "🟢Ручной режим ВКЛЮЧЕН🟢", "", keyboardPeriphery, true);
}
else if(text == "Авто режим"){
manualMode = false;
bot.sendMessageWithReplyKeyboard(chat_id, "🔴Авто режим ВКЛЮЧЕН🔴", "", keyboardPeriphery, true);
}
else if(text == "Свет ВКЛ"){
lightST = true;
applySavedColor(); // Включаем свет с сохраненным цветом
bot.sendMessageWithReplyKeyboard(chat_id, "💡Свет ВКЛЮЧЕН💡", "", keyboardPeriphery, true);
}
else if(text == "Свет ВЫКЛ"){
lightST = false;
digitalWrite(pinR, LOW);
digitalWrite(pinG, LOW);
digitalWrite(pinB, LOW);
bot.sendMessageWithReplyKeyboard(chat_id, "💡Свет ВЫКЛЮЧЕН💡", "", keyboardPeriphery, true);
}
else if(text == "Цвет света"){
bot.sendMessageWithReplyKeyboard(chat_id, "🎨Выберите цвет светодиода:", "", keyboardColors, true);
}
else if(text == "Окно"){
bot.sendMessageWithReplyKeyboard(chat_id, "🪟Управление окном:", "", keyboardWindow, true);
}
else if(text == "Открыть окно"){
servo.write(180);
servoST = true;
bot.sendMessageWithReplyKeyboard(chat_id, "🟢Окно ОТКРЫТО🟢", "", keyboardWindow, true);
}
else if(text == "Закрыть окно"){
servo.write(0);
servoST = false;
bot.sendMessageWithReplyKeyboard(chat_id, "🔴Окно ЗАКРЫТО🔴", "", keyboardWindow, true);
}
else if(text == "Пищалка ВКЛ"){
buzzerState = true;
tone(SPEAKER_PIN, 1000);
servo.attach(servoPin, 500, 2400);
bot.sendMessageWithReplyKeyboard(chat_id, "🔊Пищалка ВКЛЮЧЕНА🔊", "", keyboardPeriphery, true);
}
else if(text == "Пищалка ВЫКЛ"){
buzzerState = false;
noTone(SPEAKER_PIN);
servo.attach(servoPin, 500, 2400);
bot.sendMessageWithReplyKeyboard(chat_id, "🔊Пищалка ВЫКЛЮЧЕНА🔊", "", keyboardPeriphery, true);
}
else if(text == "Сигнализация ВКЛ"){
alarmActive = true;
bot.sendMessageWithReplyKeyboard(chat_id, "🚨Сигнализация ВКЛЮЧЕНА🚨", "", keyboardPeriphery, true);
}
else if(text == "Сигнализация ВЫКЛ"){
alarmActive = false;
bot.sendMessageWithReplyKeyboard(chat_id, "🚨Сигнализация ВЫКЛЮЧЕНА🚨", "", keyboardPeriphery, true);
}
else if(text == "Красный"){
setLEDColor(HIGH, LOW, LOW);
lightST = true; // Добавляем эту строку
bot.sendMessageWithReplyKeyboard(chat_id, "🔴Цвет изменен на КРАСНЫЙ🔴", "", keyboardColors, true);
}
else if(text == "Зеленый"){
setLEDColor(LOW, HIGH, LOW);
lightST = true; // Добавляем эту строку
bot.sendMessageWithReplyKeyboard(chat_id, "🟢Цвет изменен на ЗЕЛЕНЫЙ🟢", "", keyboardColors, true);
}
else if(text == "Синий"){
setLEDColor(LOW, LOW, HIGH);
lightST = true; // Добавляем эту строку
bot.sendMessageWithReplyKeyboard(chat_id, "🔵Цвет изменен на СИНИЙ🔵", "", keyboardColors, true);
}
else if(text == "Желтый"){
setLEDColor(HIGH, HIGH, LOW);
lightST = true; // Добавляем эту строку
bot.sendMessageWithReplyKeyboard(chat_id, "🟡Цвет изменен на ЖЕЛТЫЙ🟡", "", keyboardColors, true);
}
else if(text == "Фиолетовый"){
setLEDColor(HIGH, LOW, HIGH);
lightST = true; // Добавляем эту строку
bot.sendMessageWithReplyKeyboard(chat_id, "🟣Цвет изменен на ФИОЛЕТОВЫЙ🟣", "", keyboardColors, true);
}
else if(text == "Белый"){
setLEDColor(HIGH, HIGH, HIGH);
lightST = true; // Добавляем эту строку
bot.sendMessageWithReplyKeyboard(chat_id, "⚪Цвет изменен на БЕЛЫЙ⚪", "", keyboardColors, true);
}
else if(text == "Назад"){
bot.sendMessageWithReplyKeyboard(chat_id, "📋Главное меню:", "", keyboardMain, true);
}
else if (text == "/start") {
String welcome = "Вас приветствует бот Умного дома команды *Кибер пельмени*, " + from_name + ".\n";
welcome += "Используйте кнопки для управления:";
bot.sendMessageWithReplyKeyboard(chat_id, welcome, "Markdown", keyboardMain, true);
}
}
}
void setup() {
Serial.begin(115200);
Serial.println();
dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
servo.attach(servoPin, 500, 2400);
servo.write(0);
pinMode(chsen4, INPUT);
pinMode(PIR, INPUT);
pinMode(LDR_PIN, INPUT);
pinMode(pinR, OUTPUT);
pinMode(pinG, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(SPEAKER_PIN, OUTPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.print("Connecting to Wifi SSID ");
Serial.print(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
secured_client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("\nWiFi connected. IP address: ");
Serial.println(WiFi.localIP());
configTime(0, 0, "pool.ntp.org");
time_t now = time(nullptr);
while (now < 24 * 3600) {
delay(100);
now = time(nullptr);
}
Serial.println("🔴Сигнализация АКТИВИРОВАНА. Для деактивации используйте ультразвуковый датчик");
Serial.println("Пароль для активации/деактивации: " + passwordlog);
// Устанавливаем начальный цвет
setLEDColor(HIGH, HIGH, LOW);
}
void fastPasswordInputActivation() {
Serial.println("\n🔐 АКТИВАЦИЯ СИГНАЛИЗАЦИИ - ВВЕДИТЕ ПАРОЛЬ 🔐");
Serial.print("Введите пароль: ");
password = "";
unsigned long passwordStartTime = millis();
bool passwordEntered = false;
while (!passwordEntered && (millis() - passwordStartTime < 10000)) {
char key = keypad.getKey();
if (key != NO_KEY) {
if (key == '*') {
password = "";
Serial.println();
Serial.print("Введите пароль заново: ");
}
else if (key == '=') {
passwordEntered = true;
Serial.println();
Serial.println("Проверка пароля...");
if (password == passwordlog) {
Serial.println("✅ ПАРОЛЬ ВЕРНЫЙ! Сигнализация АКТИВИРОВАНА.");
alarmActive = true;
distanceTriggered = false;
Serial.println("Ожидание срабатывания ультразвукового датчика...");
} else {
Serial.println("❌ НЕВЕРНЫЙ ПАРОЛЬ! Сигнализация остаётся ВЫКЛЮЧЕННОЙ.");
}
}
else {
password += key;
Serial.print("*");
}
}
delay(50);
}
if (!passwordEntered) {
Serial.println();
Serial.println("⏰ ВРЕМЯ ВЫШЛО! Сигнализация остаётся ВЫКЛЮЧЕННОЙ.");
}
Serial.println("Режим активации завершен");
pirTriggered = false;
}
void fastPasswordInputDeactivation() {
Serial.println("\n🚨 ОБНАРУЖЕНО ПРИБЛИЖЕНИЕ! ВВЕДИТЕ ПАРОЛЬ ДЕАКТИВАЦИИ 🚨");
Serial.print("Введите пароль: ");
password = "";
unsigned long passwordStartTime = millis();
bool passwordEntered = false;
while (!passwordEntered && (millis() - passwordStartTime < 10000)) {
char key = keypad.getKey();
if (key != NO_KEY) {
if (key == '*') {
password = "";
Serial.println();
Serial.print("Введите пароль заново: ");
}
else if (key == '=') {
passwordEntered = true;
Serial.println();
Serial.println("Проверка пароля...");
if (password == passwordlog) {
Serial.println("✅ ПАРОЛЬ ВЕРНЫЙ! Сигнализация ОТКЛЮЧЕНА.");
alarmActive = false;
distanceTriggered = false;
noTone(SPEAKER_PIN);
Serial.println("⚠️ Сигнализация ВЫКЛЮЧЕНА. Для активации нажмите =");
} else {
Serial.println("❌ НЕВЕРНЫЙ ПАРОЛЬ! Тревога!");
tone(SPEAKER_PIN, 262, 3000);
delay(3000);
noTone(SPEAKER_PIN);
servo.attach(servoPin, 500, 2400);
bot.sendMessage(chat_id, "📡ТРЕВОГА! Введён неправильный пароль!📡", "");
Serial.println("Сигнализация остается АКТИВНОЙ");
}
}
else {
password += key;
Serial.print("*");
}
}
delay(50);
}
if (!passwordEntered) {
Serial.println();
Serial.println("⏰ ВРЕМЯ ВЫШЛО! ТРЕВОГА!");
tone(SPEAKER_PIN, 262, 5000);
delay(5000);
noTone(SPEAKER_PIN);
servo.attach(servoPin, 500, 2400);
bot.sendMessage(chat_id, "📡ТРЕВОГА! Введён неправильный пароль!📡", "");
Serial.println("Сигнализация остается АКТИВНОЙ");
}
distanceTriggered = false;
Serial.println("Режим деактивации завершен");
}
void loop() {
if (distanceTriggered && alarmActive) {
fastPasswordInputDeactivation();
}
else if (pirTriggered && !alarmActive) {
fastPasswordInputActivation();
}
t = dhtSensor.getTemperature();
h = dhtSensor.getHumidity();
CH4 = !digitalRead(chsen4);
light = digitalRead(LDR_PIN);
distance = readDistanceCM();
if (!manualMode) {
if (light) {
if (!lightST) { // Если свет был выключен
lightST = true;
applySavedColor(); // Включаем свет с сохраненным цветом
if (chat_id != "") {
bot.sendMessage(chat_id, "🟢Светодиод включен (стало темно)🟢", "");
}
Serial.println("Светодиод включен - стало темно");
}
} else {
if (lightST) { // Если свет был включен
lightST = false;
digitalWrite(pinR, LOW);
digitalWrite(pinG, LOW);
digitalWrite(pinB, LOW);
if (chat_id != "") {
bot.sendMessage(chat_id, "🔴Светодиод выключен (стало светло)🔴", "");
}
Serial.println("Светодиод выключен - стало светло");
}
}
}
if (CH4 && !last_CH4_state) {
servo.write(180);
servoST = true;
Serial.println("ОБНАРУЖЕН ГАЗ! Окно открыто!");
if (chat_id != "") {
bot.sendMessage(chat_id, "🚨🚨🚨ВНИМАНИЕ! Обнаружена утечка газа! Окно открыто🚨🚨🚨", "");
}
}
else if (!CH4 && last_CH4_state) {
servo.write(0);
servoST = false;
Serial.println("Газ устранен, окно закрыто");
if (chat_id != "") {
bot.sendMessage(chat_id, "✅СИТУАЦИЯ НОРМАЛИЗОВАЛАСЬ! Утечка газа устранена! Окно закрыто✅", "");
}
}
last_CH4_state = CH4;
val = digitalRead(PIR);
if(val == 1 && !flagPIR){
Serial.println("PIR: Обнаружено движение! Отправка в Telegram...");
if (chat_id != "") {
bot.sendMessage(chat_id, "📡Обнаружено движение!📡", "");
}
flagPIR = true;
}
if(val == 0 && flagPIR){
flagPIR = false;
}
if(distance < 200 && distance > 2 && alarmActive && !distanceTriggered){
Serial.println("Ультразвук: Обнаружено приближение! Расстояние: " + String(distance) + " см");
distanceTriggered = true;
}
if (millis() - bot_lasttime > BOT_MTBS) {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
if (numNewMessages) {
handleNewMessages(numNewMessages);
}
bot_lasttime = millis();
}
char key = keypad.getKey();
if(key == '=' && !alarmActive && !pirTriggered){
Serial.println("Запрос активации сигнализации...");
pirTriggered = true;
}
Serial.println("=== СТАТУС ===");
Serial.println("Сигнализация: " + String(alarmActive ? "🔴АКТИВНА🔴" : "🟢ВЫКЛ🟢"));
Serial.println("PIR: " + String(val ? "🔴ДВИЖЕНИЕ🔴" : "🟢НЕТ🟢"));
Serial.println("Газ: " + String(CH4 ? "🔴ОБНАРУЖЕН🔴" : "🟢НЕТ🟢"));
Serial.println("Расстояние: " + String(distance) + " см");
Serial.println("Режим: " + String(manualMode ? "🟢Ручной🟢" : "🔴Авто🔴"));
Serial.println("====================");
delay(100);
}Датчик расстояния
Клавиатура
Датчик освещённости
Сервопривод
Датчик газа
Датчик движения
Буззер
Светодиод