/*
Структура меню:
MAIN_LIGH <-> NIGHT_LIGHT <-> ALARM_CLOCK <-> WI-FI <-> Time
| | | |
Sensor On/Off Sensor On/Off Alarm On/Off WiFi SSID
| | | |
Sensor delay Sensor delay Alarm time WiFi Pass
|
Alarm duration
Передвижение по меню джойстиком:
- влево/вправо - смена меню
- вверх/вниз - смена пунктов в пределех меню данного устройства
- кнопка джойстика - вход в режим редактирования параметра
В режиме редактирования параметра (появляется курсор):
- влево/вправо - передвижение курсора влево/вправо (если переменная требует передвижения курсора)
- вверх/вниз - измненение значения параметра или буквы/цифры в текущей позиции курсора
- кнопка джойстика - выход из режима редактирования параметра с сохранением изменений
Кнопка Cancel:
- выход из режима редактирования параметра с откатом всех внесенных изменений
Синхронизация часов с сервером раз в неделю и при загрузке контроллера
При изменении пароля Wi-Fi - производится повторная синхронизация времени не дожидаясь таймера
Сенсор/будильник и основной свет:
- если сенсор или будильник включили основной свет, то по истечении заданного времени они его и выключат
- если же свет уже горел при срабатывании сенсора или будильника, то сенсор и будильник не окажут на него никакого влияния
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Array.h>
//дисплей отображения и управления меню
#include "SmartDisplay.h"
#include "SmartDisplay.cpp"
//набор меню с разными типами настроек для управления Device-ами
#include "Menu.h"
#include "MenuDelay.h"
#include "MenuDelay.cpp"
#include "MenuTime.h"
#include "MenuTime.cpp"
#include "MenuText.h"
#include "MenuText.cpp"
#include "MenuActDeact.h"
#include "MenuActDeact.cpp"
//управляемые Device
#include "Device.h"
#include "AlarmClock.h"
#include "AlarmClock.cpp"
#include "SynchroClock.h"
#include "SimpleTimer.h"
#include "SimpleTimer.cpp"
//органы управления
#include "Button.h"
#include "Button.cpp"
#include "Sensor.h"
#include "Sensor.cpp"
#include "Joystick.h"
#include "Joystick.cpp"
#define PIN_BUTTON1_MAIN_LIGHT 19
#define PIN_BUTTON2_MAIN_LIGHT 18
#define PIN_SENSOR_MAIN_LIGHT 2
#define PIN_RELAY_MAIN_LIGHT 23
#define PIN_SENSOR_NIGHT_LIGHT 4
#define PIN_RELAY_NIGHT_LIGHT 0
#define PIN_RELAY_ALARM_CLOCK 16
#define PIN_JOYSTICK_VERT 34
#define PIN_JOYSTICK_HORZ 33
#define PIN_JOYSTICK_SEL 32
#define PIN_BUTTON_CANCEL 15
#define MAX_X_MENU 5
#define MAX_Y_MENU 4
hw_timer_t *synchroTimer;
SmartDisplay<MAX_X_MENU,MAX_Y_MENU> display(0x27, 16, 2, 21, 22);
SynchroClock *sClock = SynchroClock::getInstance("Wokwi-GUEST", "");
volatile bool needSynchronization = false;
volatile bool needButton1MainLightProcess = false;
volatile bool needButton2MainLightProcess = false;
volatile bool needSensorMainLightProcess = false;
volatile bool needSensorNightLightProcess = false;
Device mainLight(PIN_RELAY_MAIN_LIGHT);
Button<Device> button1MainLight(&mainLight, &Device::switchover, PIN_BUTTON1_MAIN_LIGHT);
Button<Device> button2MainLight(&mainLight, &Device::switchover, PIN_BUTTON2_MAIN_LIGHT);
SimpleTimer<1> timerMainLight(10);
Sensor<1,1> sensorMainLight(sClock, "7:00", "23:00", PIN_SENSOR_MAIN_LIGHT);
Menu menuMainLightLabel("MAIN LIGHT MENU");
MenuActDeact<Sensor<1,1>> menuMainLightSensorOnOff("Sensor On/Off", &sensorMainLight, &Sensor<1,1>::isActivated, &Sensor<1,1>::activate);
MenuDelay<SimpleTimer<1>> menuDelayMainLight("Sensor delay", &timerMainLight, &SimpleTimer<1>::getDelay, &SimpleTimer<1>::setDelay, 10, 600);
Device nightLight(PIN_RELAY_NIGHT_LIGHT);
SimpleTimer<1> timerNightLight(10);
Sensor<1,1> sensorNightLight(sClock, "23:00", "7:00", PIN_SENSOR_NIGHT_LIGHT);
Menu menuNightLightLabel("NIGHT LIGHT MENU");
MenuActDeact<Sensor<1,1>> menuNightLightSensorOnOff("Sensor On/Off", &sensorNightLight, &Sensor<1,1>::isActivated, &Sensor<1,1>::activate);
MenuDelay<SimpleTimer<1>> menuDelayNightLight("Sensor delay", &timerNightLight, &SimpleTimer<1>::getDelay, &SimpleTimer<1>::setDelay, 10, 60);
Device alarmDevice(PIN_RELAY_ALARM_CLOCK);
AlarmClock<0,1,2> alarmClock(sClock, "00:00");
Menu menuAlarmClockLabel("ALARM CLOCK MENU");
SimpleTimer<2> timerAlarmClock(10);
MenuActDeact<AlarmClock<0,1,2>> menuAlarmClockOnOff("Alarm On/Off", &alarmClock, &AlarmClock<0,1,2>::isActivated, &AlarmClock<0,1,2>::activate);
MenuTime<AlarmClock<0,1,2>> menuTimeAlarmClock("Alarm time", false, &alarmClock, &AlarmClock<0,1,2>::getAlarmTime, &AlarmClock<0,1,2>::setAlarmTime);
MenuDelay<SimpleTimer<2>> menuDelayAlarmClock("Alarm duration", &timerAlarmClock, &SimpleTimer<2>::getDelay, &SimpleTimer<2>::setDelay, 10, 600);
Menu menuWiFiLabel("WI-FI MENU");
MenuText<SynchroClock> menuWiFiSSID("WiFi SSID", sClock, &SynchroClock::getSSID, &SynchroClock::setSSID);
MenuText<SynchroClock> menuWiFiPassword("WiFi Pass", sClock, &SynchroClock::getPassword, &SynchroClock::setPassword);
MenuTime<SynchroClock> menuTimeTime("Time", true, sClock, &SynchroClock::getTime, &SynchroClock::setTime);
void setup()
{
Serial.begin(115200);
delay(1000);
display.begin(16,2);
display.addCancelButton(PIN_BUTTON_CANCEL);
display.addJoystick(PIN_JOYSTICK_HORZ, PIN_JOYSTICK_VERT, PIN_JOYSTICK_SEL);
//добавляем в управление сенсорам таймеры
sensorMainLight.addTimer(&timerMainLight);
sensorNightLight.addTimer(&timerNightLight);
//добавляем в управление будильнику таймер
alarmClock.addTimer(&timerAlarmClock);
//добавялем в управление таймерам Девайсы
timerMainLight.addDevice(&mainLight);
timerNightLight.addDevice(&nightLight);
timerAlarmClock.addDevice(&alarmDevice);
timerAlarmClock.addDevice(&mainLight);
//создаем листы меню (вертикальные)
Array<Menu*,MAX_Y_MENU> vMainLight;
Array<Menu*,MAX_Y_MENU> vNightLight;
Array<Menu*,MAX_Y_MENU> vAlarmClock;
Array<Menu*,MAX_Y_MENU> vWiFi;
Array<Menu*,MAX_Y_MENU> vTime;
vMainLight.push_back(&menuMainLightLabel);
vMainLight.push_back(&menuMainLightSensorOnOff);
vMainLight.push_back(&menuDelayMainLight);
vNightLight.push_back(&menuNightLightLabel);
vNightLight.push_back(&menuNightLightSensorOnOff);
vNightLight.push_back(&menuDelayNightLight);
vAlarmClock.push_back(&menuAlarmClockLabel);
vAlarmClock.push_back(&menuAlarmClockOnOff);
vAlarmClock.push_back(&menuTimeAlarmClock);
vAlarmClock.push_back(&menuDelayAlarmClock);
vWiFi.push_back(&menuWiFiLabel);
vWiFi.push_back(&menuWiFiSSID);
vWiFi.push_back(&menuWiFiPassword);
vTime.push_back(&menuTimeTime);
//добавляем все листы в дисплей
display.addMenu(vMainLight);
display.addMenu(vNightLight);
display.addMenu(vAlarmClock);
display.addMenu(vWiFi);
display.addMenu(vTime);
display.initialize();
//первый таймер отдаем на синхронизацию часов раз в неделю
//synchroTimer = timerBegin(1, APB_CLK_FREQ/1000000, true);//таймер 0 с делителем 80 APB_CLK_FREQ = 80000000, true - счет вверх
//timerAttachInterrupt(synchroTimer, [&needSynchronization](){needSynchronization = true;}, true);
//timerAlarmWrite(synchroTimer, 7*24*3600*1000000, true);
//timerAlarmEnable(synchroTimer);
synchroTimer = timerBegin(1000000);
timerAttachInterrupt(synchroTimer, [&needSynchronization](){needSynchronization = true;});
timerAlarm(synchroTimer, 604800000000, true, 0);
//постановка задач по обработке кнопок и сенсоров по прерываниям
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON1_MAIN_LIGHT), [&needButton1MainLightProcess](){needButton1MainLightProcess = true;}, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON2_MAIN_LIGHT), [&needButton2MainLightProcess](){needButton2MainLightProcess = true;}, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_SENSOR_MAIN_LIGHT), [&needSensorMainLightProcess](){needSensorMainLightProcess = true;}, RISING);
attachInterrupt(digitalPinToInterrupt(PIN_SENSOR_NIGHT_LIGHT), [&needSensorNightLightProcess](){needSensorNightLightProcess = true;}, RISING);
//первая синхроинзация времени, также принудительная попытка синхронизации будет происходить при смене пароля WiFi
sClock->syncronizeTime();
Serial.println("Controller initialized.");
}
void loop()
{
delay(10);//для облегчения симуляции
display.process();
alarmClock.process();
if(needSynchronization) {sClock->syncronizeTime();needSynchronization = false;}
if(needButton1MainLightProcess) {button1MainLight.process();needButton1MainLightProcess = false;}
if(needButton2MainLightProcess) {button2MainLight.process();needButton2MainLightProcess = false;}
if(needSensorMainLightProcess) {sensorMainLight.process();needSensorMainLightProcess = false;}
if(needSensorNightLightProcess) {sensorNightLight.process();needSensorNightLightProcess = false;}
if(timerMainLight.isGoing()) {timerMainLight.process();}
if(timerNightLight.isGoing()) {timerNightLight.process();}
if(timerAlarmClock.isGoing()) {timerAlarmClock.process();}
}