Проект представляет собой подобие суточного таймера, который включает освещение в доме, тем самым имитирует присутствие хозяев. Подробнее про алгоритм работы рассказано в видео, суть его в следующем, таймер имеет два выхода на релейный модуль, которые управляют освещением в коридоре (комнате) и на улице. Первый выход, является суточным таймером в своем исходном виде, с одной разницей, его расписание генерируется ежедневно псевдослучайным образом в заданных приделах. Второй выход, во время работы первого выхода, также псевдослучайно, включает на небольшей интервал с большим перерывом освещение на улице.
Чтобы повторить проект понадобятся часы реального времени, модуль на DS1307 или DS3231 (рекомендуется), LCD Keypad Shield, можно и текстовый LCD 16х2 отдельно. Можно использовать графический OLED дисплей SSD1306 0.96 128×64, для него отдельная версия исходного кода или вообще не подключать дисплей, он необходим только для контроля установленного времени. Еще понадобится релейный модуль и Arduino UNO или её дешевый аналог.
схема подключения модулей к LCD Keypad Shield, который одевается на Arduino UNO
установка текущего времени в проекте не предусмотрена, поэтому нужно заранее установить время в модуль часов.
сам код с комментариями для LCD Keypad Shield
// Эффект присутствия хозяев в доме или на даче // для LCD Keypad Shield // https://www.youtube.com/watch?v=imEvfyIiwtY #include <Wire.h> #include <LiquidCrystal.h> #include <EEPROM.h> #define OUT1 12 //выходы на релейный модуль #define OUT2 13 LiquidCrystal lcd(8,9,4,5,6,7); byte tm; byte timerOut2 = 2; ///// часы .. byte decToBcd(byte val){ return ( (val/10*16) + (val%10) ); } byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) ); } void setDateDs1307(byte second, // 0-59 byte minute, // 0-59 byte hour, // 1-23 byte dayOfWeek, // 1-7 byte dayOfMonth, // 1-28/29/30/31 byte month, // 1-12 byte year) // 0-99 { Wire.beginTransmission(0x68); Wire.write(0); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); Wire.write(decToBcd(dayOfWeek)); Wire.write(decToBcd(dayOfMonth)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.endTransmission(); } void getDateDs1307(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(0x68); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(0x68, 7); *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } void setup(){ // Serial.begin(9600); Wire.begin(); lcd.begin(16,2); pinMode(OUT1, OUTPUT); pinMode(OUT2, OUTPUT); digitalWrite(OUT1, LOW); digitalWrite(OUT2, LOW); randomSeed(analogRead(1)); // timerReset(); // для отладки } void loop(){ byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); lcdPrint(); // вывод на экран if (12 == hour && // в 12:00 генерируем новое расписание 0 == minute && 0 == second) timerReset(); // сверяем расписание с текущим временем и управляем реле if (EEPROM.read(0) == hour && EEPROM.read(1) == minute) digitalWrite(OUT1, HIGH); if (EEPROM.read(2) == hour && EEPROM.read(3) == minute) digitalWrite(OUT1, LOW); if (digitalRead(OUT1)){ // если первый выход выключен, то и со вторым нечего делать ненужно if (tm != minute){ // таймер для второго выхода tm = minute; // timerOut2--; } if (timerOut2 == 0){ // в функции random(40, 60) диапазон для второго выхода в минутах if(digitalRead(OUT2)) timerOut2 = random(40, 60); // выключение на 40-59 минут else timerOut2 = random(3, 7); //включение на 3-6 мин digitalWrite(OUT2, !digitalRead(OUT2)); } } else digitalWrite(OUT2, LOW); // } /// вывод инфы на экран 16x2// void lcdPrint(){ char time[9], data[11], onOff[23], off[9]; byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); /// время snprintf(time, sizeof(time), "%02d:%02d:%02d", hour, minute, second); snprintf(data, sizeof(data), "%02d/%02d/%02d", dayOfMonth, month, hour); lcd.setCursor(0, 0); lcd.print(time); /// on/off snprintf(onOff, sizeof(onOff), " %02d:%02d/%02d:%02d|", EEPROM.read(0), EEPROM.read(1), EEPROM.read(2), EEPROM.read(3)); lcd.setCursor(0, 1); lcd.print(onOff); lcd.print(timerOut2); /// статус lcd.setCursor(9, 0); if(digitalRead(OUT1)) lcd.print("ON "); else lcd.print("OFF"); if(digitalRead(OUT2)) lcd.print(" ON "); else lcd.print(" OFF"); } ///////////////////// void timerReset(){ // генерирует раcписание работы для первого выхода и для всего устройства тоже EEPROM.write(0, 20); //часы вкл, постоянно в 8 вечера EEPROM.write(1, random(0, 60)); //минуты вкл 0-59 EEPROM.write(2, random(22, 24)); //часы выкл 22-23 EEPROM.write(3, random(10, 45)); //минуты выкл 10-44 delay(1100); // нужно подождать, иначе функция вызавиться повторно }
и для OLED 0.96 128×64
// Эффект присутствия хозяев в доме или на даче // для OLED // https://www.youtube.com/watch?v=imEvfyIiwtY #include <OLED_I2C.h> #include <Wire.h> #include <EEPROM.h> #define OUT1 3 //выходы на реле #define OUT2 4 OLED myOLED(SDA, SCL, 8); extern uint8_t SmallFont[]; byte tm; byte timerOut2 = 2; ///// часы .. byte decToBcd(byte val){ return ( (val/10*16) + (val%10) ); } byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) ); } void setDateDs1307(byte second, // 0-59 byte minute, // 0-59 byte hour, // 1-23 byte dayOfWeek, // 1-7 byte dayOfMonth, // 1-28/29/30/31 byte month, // 1-12 byte year) // 0-99 { Wire.beginTransmission(0x68); Wire.write(0); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); Wire.write(decToBcd(dayOfWeek)); Wire.write(decToBcd(dayOfMonth)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.endTransmission(); } void getDateDs1307(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(0x68); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(0x68, 7); *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } void setup(){ // Serial.begin(9600); myOLED.begin(); myOLED.setBrightness(1); myOLED.setFont(SmallFont); pinMode(OUT1, OUTPUT); pinMode(OUT2, OUTPUT); digitalWrite(OUT1, HIGH); randomSeed(analogRead(1)); // timerReset(); // для отладки myOLED.clrScr(); } void loop(){ byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); lcdPrint(); // вывод на экран if (12 == hour && // в 12 дня генерируем новое расписание 0 == minute && 0 == second) timerReset(); if (EEPROM.read(0) == hour && EEPROM.read(1) == minute) digitalWrite(OUT1, HIGH); if (EEPROM.read(2) == hour && EEPROM.read(3) == minute) digitalWrite(OUT1, LOW); if (digitalRead(OUT1)){ // если первый выход выключен, то и со вторым нечего делать ненужно if (tm != minute){ // таймер для второго выхода tm = minute; // timerOut2--; } if (timerOut2 == 0){ if(digitalRead(OUT2)) timerOut2 = random(40, 60); // если свет включен else timerOut2 = random(3, 7); //если выключен, включаем на 3-7 мин digitalWrite(OUT2, !digitalRead(OUT2)); } } else digitalWrite(OUT2, LOW); // } /// вывод инфы на экран oled// void lcdPrint(){ char time[9], data[11], onOff[23], off[9]; byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); /// время snprintf(time, sizeof(time), "%02d:%02d:%02d", hour, minute, second); snprintf(data, sizeof(data), "%02d/%02d/%02d", dayOfMonth, month, hour); myOLED.setFont(SmallFont); myOLED.print(time, LEFT, 0); myOLED.print(data, LEFT, 9); /// on/off snprintf(onOff, sizeof(onOff), "1.on/off %02d:%02d/%02d:%02d", EEPROM.read(0), EEPROM.read(1), EEPROM.read(2), EEPROM.read(3)); myOLED.print(onOff, LEFT, 25); myOLED.print("2.", LEFT, 34); myOLED.printNumI(timerOut2, 12, 34); /// статус if(digitalRead(OUT1)) myOLED.print("|ON ", 100, 0); else myOLED.print("|OFF", 100, 0); if(digitalRead(OUT2)) myOLED.print("|ON ", 100, 9); else myOLED.print("|OFF", 100, 9); myOLED.update(); } void timerReset(){ EEPROM.write(0, 19); //часы вкл EEPROM.write(1, random(0, 59)); //минуты вкл EEPROM.write(2, random(0, 2)); //часы выкл EEPROM.write(3, random(30, 59)); //минуты выкл delay(1000); // нужно подождать, иначе функция вызавиться повторно }