// https://github.com/netology-code/iot-diplom
//#include <esp32-hal-timer.h>
#include <TimeLib.h>
#include <LiquidCrystal.h>
#include <Keypad.h>
#include "MenuSmartHome.h"
#include "AlarmClock.h"
#include "MoveSensor.h"
#include "NetworkConnection.h"
// Назначения пинов для кнопок
const int buttonLight1 = 35; // Кнопка1 включения света
const int buttonLight2 = 34; // Кнопка2 включения света
const int buttonUp = 16; // Кнопка меню вверх UART2 Rx
//const int buttonLeft = 2; // Кнопка меню влево - не хватило пинов - вроде обошлись
const int buttonRight = 39; // Кнопка меню вправо (SensVN)
const int buttonDown = 36; // Кнопка меню вниз (SensVP)
// Назначения пинов для подключения клавиатуры
const int R1 = 32;
const int R2 = 13;
const int R3 = 15;
const int R4 = 18;
const int C1 = 17; ///UART2 Tx
const int C2 = 4;
const int C3 = 19;
const int C4 = 2;
// Параметры клавиатуры
const byte Rows = 4; // количество строк на клавиатуре
const byte Cols = 4; // количество столбцов на клавиатуре
char keymap[Rows][Cols] =
{
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rPins[Rows] = {R1, R2, R3, R4};
byte cPins[Cols] = {C1, C2, C3, C4};
// Создадим объект клавиатуры
Keypad kpd = Keypad(makeKeymap(keymap), rPins, cPins, Rows, Cols);
// Назначение пинов для управления реле
const int relayMainLight_out = 21; // Управление реле основного света
const int relayNightLight_out = 22; // Управление реле ночного света
const int relayAlarm_out = 23; // Управление реле дополнительной нагрузки для будильника
const int moveSensorSignal = 5; // Вход от датчика движения
// Сигналы
volatile bool buttonLight1_Pressed = false; // Сигнал нажатия кнопки buttonLight1
volatile bool buttonLight2_Pressed = false; // Сигнал нажатия кнопки buttonLight2
volatile bool buttonUp_Pressed = false; // Сигнал нажатия кнопки buttonUp
volatile bool buttonLeft_Pressed = false; // Сигнал нажатия кнопки buttonLeft
volatile bool buttonRight_Pressed = false; // Сигнал нажатия кнопки buttonRight
volatile bool buttonDown_Pressed = false; // Сигнал нажатия кнопки buttonDown
bool MotionDetected = false; // Сигнал-триггрер о детектировании движения
bool MotionEnded = false; // Сигнал окончания обработки событий детектора движения
volatile unsigned long ButtonDebounceTimer = 0; // Таймер для фильтрации дребезга кнопок
volatile unsigned long UpdateTimer = 0; // Таймер для обновления состояний
volatile bool TimeToUpdate = false;
const unsigned int ButtonDelayTime = 200; //Фильтрация кнопок 200мс
const unsigned int UpdateTimeDelay = 10; // Обновляем всё каждые 10мс. Лучше конечно более дифференцированно: будильник можно и раз в минуту обновлять...
const unsigned int MoveTimeDelay = 5000; // Удержание сигнала детектора движения
// Создадим LCD дисплей
LiquidCrystal lcd(12, 14, 27, 26, 25, 33); // LCD дисплей
// Праметры умного дома
bool Night_Light_Activate = true; // Разрешение/запрет включения ночной подсветки по датчику движения
unsigned int Night_Light_TimeOut = 10; // Время активности ночной подсветки после срабатывания датчика движения в диапазоне от 10 до 60 секунд
bool Main_Light_Activate = 10; // Разрешение/запрет включения основного света по датчику движения;
unsigned int Main_Light_TimeOut = 10; // Время активности основного света после срабатывания датчика движения в диапазоне от 10 до 600 секунд
time_t Alarm_Time; // Время срабатывания будильника -- нужно опередить тип
bool Alarm_Activate = false; // Разрешение/запрет будильника
unsigned int Alarm_Load_TimeOut = 10; // Длительность подачи питания на дополнительную нагрузку при срабатывании будильника в диапазоне от 10 до 600 секунд
time_t CurrentTime; // Текущее время
bool Main_Light_Ena = false; // Состояние основного освещения
bool Night_Light_Ena = false; // Состояние ночного освещения
bool Main_Light_Ena_prev = false; // Предыдущее состояние основного освещения
bool Night_Light_Ena_prev = false; // Предыдущее состояние основного освещения
bool UpdateWiFi = false; //Сигнал для установки соединения в случае изменения ssid или password
String ssid = "Wokwi-GUEST";
String password = "";
//Создадим объект меню
MenuSmartHome menu (&Night_Light_Activate,
&Night_Light_TimeOut,
&Main_Light_Activate,
&Main_Light_TimeOut,
&Alarm_Time,
&Alarm_Activate,
&Alarm_Load_TimeOut,
&CurrentTime,
&Main_Light_Ena,
&Night_Light_Ena,
&ssid,
&password,
&lcd,
&kpd,
&UpdateWiFi
);
// Создадим объект будильник
AlarmClock MyAlarm (&relayAlarm_out,
&Alarm_Time,
&CurrentTime,
&Alarm_Load_TimeOut,
&Alarm_Activate,
&Main_Light_Ena);
// Создадим объект датчик движения
MoveSensor MySensor (&CurrentTime,
&Night_Light_TimeOut,
&Main_Light_TimeOut,
&Night_Light_Activate,
&Main_Light_Activate,
&Night_Light_Ena,
&Main_Light_Ena,
&MotionDetected);
// Создадим объект NetworkConnection
NetworkConnection MyConnection(&CurrentTime,
&ssid,
&password);
void setup() {
// Подвяжем прерывания на сигналы кнопок и датчика движения
attachInterrupt(digitalPinToInterrupt(buttonLight1), handle_buttonLight1, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonLight2), handle_buttonLight2, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonRight), handle_buttonRight, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonDown), handle_buttonDown, FALLING);
attachInterrupt(digitalPinToInterrupt(buttonUp), handle_buttonUp, FALLING);
attachInterrupt(digitalPinToInterrupt(moveSensorSignal), handle_MotionSensor, RISING);
//attachInterrupt(digitalPinToInterrupt(moveSensorSignal), handle_MotionEnded, FALLING);
// Зададим режим работы выводам Arduino
pinMode(buttonLight1, INPUT_PULLUP);
pinMode(buttonLight2, INPUT_PULLUP);
pinMode(buttonRight, INPUT_PULLUP);
pinMode(buttonRight, INPUT_PULLUP);
pinMode(buttonDown, INPUT_PULLUP);
pinMode(buttonUp, INPUT_PULLUP);
pinMode(relayMainLight_out, OUTPUT);
pinMode(relayNightLight_out, OUTPUT);
pinMode(relayAlarm_out, OUTPUT);
pinMode(moveSensorSignal, INPUT_PULLDOWN);
Serial.begin(115200);
/*
delay(1000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Соединяемся с Wi-Fi..");
}
Serial.println("Соединение с Wi-Fi установлено");
*/
lcd.begin(16, 2); // Инициализация LCD дисплея 16x2
lcd.setCursor(0, 0);
lcd.print(" Smart Home");
lcd.setCursor(0, 1);
lcd.print(" _______");
//Протестируем выходы
digitalWrite(relayMainLight_out, HIGH);
delay(500);
digitalWrite(relayNightLight_out, HIGH);
delay(500);
digitalWrite(relayAlarm_out, HIGH);
delay(500);
digitalWrite(relayAlarm_out, LOW);
digitalWrite(relayNightLight_out, LOW);
digitalWrite(relayMainLight_out, LOW);
setTime(12, 30, 0, 17, 10, 2023); // Установим какое-то начальное время (часы, минуты, секунды, день, месяц, год)
CurrentTime = now();
Alarm_Time = now(); // По-умолчанию будильник зачем-то настроен на время, заданное при включении
// Создадим таймер для обновления разных событий
/*
hw_timer_t *timer = NULL;
timer = timerBegin(0, 80, true); //Номер таймера и делитель
// Период и функцию обратного вызова
timerAttachInterrupt(timer, &timerCallback, true);
timerAlarmWrite(timer, 1000000, true); // Период в микросекундах
timerAlarmEnable(timer);
*/
if (MyConnection.updateConnection()) {
MyConnection.updateTime();
}
UpdateTimer = millis();
}
void loop() {
if (buttonLight1_Pressed or buttonLight2_Pressed) {
if ((ButtonDebounceTimer + ButtonDelayTime ) < millis()) {
buttonLight1_Pressed = false;
buttonLight2_Pressed = false;
Main_Light_Ena = !Main_Light_Ena;
Serial.print("Main_Light_Ena = ");
Serial.println(Main_Light_Ena);
}
}
if (buttonRight_Pressed) {
if ((ButtonDebounceTimer + ButtonDelayTime ) < millis())
{
buttonRight_Pressed = false;
Serial.println("buttonRight_Pressed");
menu.MenuSetParam();
}
}
if (buttonDown_Pressed) {
if ((ButtonDebounceTimer + ButtonDelayTime ) < millis())
{
buttonDown_Pressed = false;
menu.MenuInrease();
Serial.println("buttonDown_Pressed");
}
}
if (buttonUp_Pressed) {
if ((ButtonDebounceTimer + ButtonDelayTime ) < millis())
{
buttonUp_Pressed = false;
menu.MenuDecrease();
Serial.println("buttonUp_Pressed");
}
}
// Пришла пора обновить всё
if ((UpdateTimer + UpdateTimeDelay) < millis())
{
Night_Light_Control();
Main_Light_Control();
menu.MenuEnterParam();
MyAlarm.updateAlarm();
MySensor.updateMoveSensor();
menu.ShowTime();
if (UpdateWiFi == true) {
UpdateWiFi = false;
if (MyConnection.updateConnection()) {
MyConnection.updateTime();
}
}
}
if (MotionDetected) {
if ((ButtonDebounceTimer + MoveTimeDelay) < millis())
{
MotionDetected = false;
Serial.println("Motion Ended!");
}
}
}
void handle_buttonLight1() {
ButtonDebounceTimer = millis();
buttonLight1_Pressed = true;
}
void handle_buttonLight2() {
ButtonDebounceTimer = millis();
buttonLight2_Pressed = true;
}
void handle_buttonDown() {
ButtonDebounceTimer = millis();
buttonDown_Pressed = true;
}
void handle_buttonRight() {
ButtonDebounceTimer = millis();
buttonRight_Pressed = true;
}
void handle_buttonUp() {
ButtonDebounceTimer = millis();
buttonUp_Pressed = true;
}
void handle_MotionSensor() {
ButtonDebounceTimer = millis();
Serial.println("Motion Detected!");
MotionDetected = true;
}
void Main_Light_Control() {
if (Main_Light_Ena != Main_Light_Ena_prev) {
Main_Light_Ena_prev = Main_Light_Ena;
digitalWrite(relayMainLight_out, Main_Light_Ena);
}
}
void Night_Light_Control() {
if (Night_Light_Ena != Night_Light_Ena_prev) {
Night_Light_Ena_prev = Night_Light_Ena;
digitalWrite(relayNightLight_out, Night_Light_Ena);
}
}
/*
void timerCallback() {
MyAlarm.updateAlarm();
Serial.println("Alarm Updated");
}
*/
Light1
Light2
Up
Down
SET
Menu buttons
Alarm
Night Light
Main Light
Move Sensor