/*
2024.01.15
Часы на Arduino UNO и ZS-042 с управлением от ТВ-пультов.
См, также, на сайте roamer55.ru
*/
//--------------------------------
//Используемые библиотеки
#include "IRremote.h"
#include "DS3231.h"
#include "Wire.h"
#include "TM1637.h"
//--------------------------------
//--------------------------------
bool Mode_Is_Work = true;   //Режим работы:  =true-РАБОТА; =false-УСТАНОВКА часов/будильника
//--------------------------------
//--------------------------------
#define MODE_set_LED 9  //пин для ЗЕЛЕНОГО светодиода: настройка будильника и часов
#define TIME_set_LED 8  //пин для БЕЛОГО светодиода: настройка часов
//--------------------------------
//--------------------------------
//Коды внутренних команд Устройства
byte DevCom_is_None = 0;
byte DevCom_is_Work = 1;
byte DevCom_is_Set  = 2;
byte DevCom_is_Set_Time  = 3;
byte DevCom_is_Set_Date  = 4;
byte DevCom_is_Set_Alarm  = 5;
byte DevCom_is_alarm_view = 6;
byte DevCom_is_alarm_enable = 7;
byte DevCom_is_alarm_disable = 8;
byte DevCom_is_alarm_sound_enable = 9;
byte DevCom_is_alarm_sound_disable = 10;
byte DevCom_is_time_blink_enable_disable = 11;
byte Device_IdCommand = DevCom_is_None;
byte Device_IdCommand_old = Device_IdCommand;
byte Device_IdCommand_buf = DevCom_is_None;
//--------------------------------
//--------------------------------
//Часы ZS-042
DS3231 Clock;  //Создание объекта Clock
//.................................
//Используются для "обслуживания" библиотеки "DS3231.h"
bool Century = false;
bool h12;
bool PM;
//.................................
//.................................
byte YeMin = 20; //Минимально допустимый год
                 //Если при включении питания значение года на часах меньше, чем это
                 //то в ZS-042 записывается дата: Ye0, Mo0, Da0, DoW0, Ho0, Mi0, Se0. 
//.................................
//.................................
//Дата и Время по умолчанию (если при включении питания значение года на часах меньше, чем YeMin)
byte Ye0 = 24;
byte Mo0 = 1;   
byte Da0 = 1;
byte DoW0 = 1;
byte Ho0 = 0;
byte Mi0 = 1;
byte Se0 = 0;
//.................................
//.................................
//Текущие Дата и Время
byte Ye;
byte Mo;
byte Da;
byte DoW;
byte Ho;
byte Mi;
byte Se;
//.................................
//.................................
//Буферные значения Минуты и Секунды "Часов".
//Используются для квантования промежутков времени 
//обновления Даты и Времени "Часов" на дисплее
byte MiOld;
byte SeOld;
//.................................
//.................................
//Строковые представления Даты и Времени.
//Могут потребоваться при отладке с использование Serial.
//Вычисляются в функциях: DateToStr() и TimeToStr().
//String DateS = "";
//String TimeS = "";
//.................................
//--------------------------------
//--------------------------------
//Будильник
//.................................
//Управление включением/выключением режима "Будильник"
//и его атрибутами
bool alarm_yes = false;      // =true - будильник включен, иначе - вЫключен
bool alarm_sound_yes = true; // =true - звук будильника включен, иначе - вЫключен
int alarm_Len = 500;         //длительность звукового сигнала (миллисекунд)
int alarm_count = 3;         //кол-во звуковых сигналов
//.................................
//.................................
int alarm_Ho = 0;  // часы срабатывания "Будильника"
int alarm_Mi = 0;  //минуты срабатывания "Будильника"
//.................................
//.................................
//Элементы схемы "Будильника"
#define alarm_Buzzer 5         // пин для зуммера
#define alarm_LED 12           // пин для КРАСНОГО светодиода "Будильник сработал"
#define alarm_yes_LED 11       // пин для ЖЕЛТОГО светодиода "Будильник включен"
#define alarm_sound_yes_LED 10 //пин для СИНЕГО светодиода: пищать
//--------------------------------
//--------------------------------
//Дисплей-индикатор 3642BH
//.................................
#define CLK 2                       // Контакт CLK
#define DIO 3                       // Контакт DIO
#define BRIGHT_TYPICAL  7           // Яркость дисплея от 0 до 7
//.................................
//.................................
TM1637 tm1637(CLK,DIO);             // Создание объекта tm1637
int8_t NumTab[] = {0,0,0,0};        // Создание массива данных (для tm1637)
//.................................
//.................................
//"Мигание" двоетчия на дисплее при визуализации ЧЧ:ММ на "Часах"
bool time_delim_blink_trig = false; //триггер, обеспечиваюший "мигание" двоеточия на дисплее
bool time_delim_blink = true;       //если =true, то "мигание" разрешено, =false - нет
//.................................
//--------------------------------
//--------------------------------
//ИК-приемник. KY-022
IRrecv irrecv(4); // Создание объекта irrecv (подключен к 4-му выводу Arduino UNO)
decode_results results; //Переменная, где хранитсяинформация, полученная от ТВ-пульта
//.................................
//Унифицированные коды кнопок ТВ-пультов
int ky022_id_com_is_unknown = -1; //Неопределено
int ky022_id_com_is_star=91;  //Звезда
int ky022_id_com_is_diez=92;  //Диез
int ky022_id_com_is_repeat = 999; //Повтор
int ky022_id_com_is_btn_red = 35;     //Кнопка розовая/красная
int ky022_id_com_is_btn_green = 36;   //Кнопка зеленая
int ky022_id_com_is_btn_yellow = 37;  //Кнопка желтая
int ky022_id_com_is_btn_blue = 38;    //Кнопка синяя
int ky022_id_com_is_vol_plus = 39;
int ky022_id_com_is_vol_minus = 40;
int ky022_id_com_is_ch_plus = 41;
int ky022_id_com_is_ch_minus = 42;
int ky022_id_com_is_up = 21;     // ^
int ky022_id_com_is_left = 22;   // <
int ky022_id_com_is_right = 23;  // >
int ky022_id_com_is_down = 24;   // V
int ky022_id_com_is_ok = 25;     // OK
int ky022_id_com_is_enter = 26; //Enter
int ky022_id_com_is_exit =  27; //Exit
int ky022_id_com_is_0 = 0; //0
int ky022_id_com_is_1 = 1; //1
int ky022_id_com_is_2 = 2; //2
int ky022_id_com_is_3 = 3; //3
int ky022_id_com_is_4 = 4; //4
int ky022_id_com_is_5 = 5; //5
int ky022_id_com_is_6 = 6; //6
int ky022_id_com_is_7 = 7; //7
int ky022_id_com_is_8 = 8; //8
int ky022_id_com_is_9 = 9; //9
int ky022_id_command = ky022_id_com_is_unknown;
//.................................
//--------------------------------     


void setup()
{
  //.................................
  //Режимы пинов, используемые для светодиодов и зуммера
  pinMode(alarm_yes_LED, OUTPUT); //желтый светодиод
  digitalWrite(alarm_yes_LED, LOW);
  pinMode(alarm_sound_yes_LED, OUTPUT); //синий светодиод
  digitalWrite(alarm_sound_yes_LED, LOW);
  pinMode(MODE_set_LED, OUTPUT); //зеленый светодиод
  digitalWrite(MODE_set_LED, LOW);
  pinMode(TIME_set_LED, OUTPUT);  //белый светодиод
  digitalWrite(TIME_set_LED, LOW);
  pinMode(alarm_Buzzer, OUTPUT);
  pinMode(alarm_LED, OUTPUT);  //красный светодиод
  digitalWrite(alarm_LED, LOW);
  //.................................
  //.................................
  Wire.begin(); //Инициализация библиотеки Wire и подключение к шине I2C
  //.................................
  //.................................
  //Часы
  Clock.setClockMode(false);  //24-часовой формат
  if (Clock.getYear() < YeMin) 
  {
    //Установка ЧЧ:ММ "Часов" по умолчанию, если они "слетели"
     Clock.setYear(Ye0);
     Clock.setMonth(Mo0);
     Clock.setDate(Da0);
     Clock.setDoW(DoW0);
     Clock.setHour(Ho0);
     Clock.setMinute(Mi0);
     Clock.setSecond(Se0);
  }
  //.................................
  //...................
  tm1637.init();                    // Инициализируем дисплей
  tm1637.set(BRIGHT_TYPICAL);       // Устанавливаем яркость дисплея
  //Time_View(); //Визуализировать текущее время
  //...................
  //.................................
  irrecv.enableIRIn(); // Инициальзация и "старт" ИК-приемника
  //.................................
  //.................................
  device_test(); //Тестирование компонентов Устройства
  //.................................
  //.................................
  //Текущие Дата и Время
  NOW_Get(); //Прочитать из ZS-042
  MiOld = Mi;
  SeOld = Se;
  //.................................
  //.................................
  Time_View(); //Визуализировать текущее время
  //.................................
  //.................................
  LED_state_Actual(); //Актуальное состояние светодиодов
  //.................................
}


void loop()
{
  //========================
  //Считывание данных с ТВ-пультов
  ky022_id_command = irrecv_comm_get(); //Получить код нажатой кнопки
  if ((ky022_id_command == ky022_id_com_is_ok) || (ky022_id_command == ky022_id_com_is_enter))
  {
      device_test(); //Тестирование компонентов Устройства
      LED_state_Actual(); //Актуальное состояние светодиодов
      ky022_id_command = ky022_id_com_is_unknown;
  }
  Device_IdCommand = device_comm_get(ky022_id_command);
  if (Device_IdCommand == DevCom_is_Work) { Mode_Is_Work = true; } 
  if (Device_IdCommand == DevCom_is_Set) { Mode_Is_Work = false; } 
  if (Device_IdCommand == DevCom_is_alarm_view) { Mode_Is_Work = false; } 
  if (Device_IdCommand == DevCom_is_Work) { Mode_Is_Work = true; } 
  //========================

  //========================
  if (Mode_Is_Work == true) //Режим "Часы"
  {
     //--------------------------------     
     //.................................
     //Включить "Будильник"
     if (Device_IdCommand == DevCom_is_alarm_enable) { alarm_yes = true; LED_state_Actual(); } 
     //.................................
     //.................................
     //Выключить "Будильник"
     if (Device_IdCommand == DevCom_is_alarm_disable) { alarm_yes = false; LED_state_Actual(); } 
     //.................................
     //.................................
     //Включить звук "Будильника"
     if (Device_IdCommand == DevCom_is_alarm_sound_enable) { alarm_sound_yes = true; LED_state_Actual(); } 
     //.................................
     //.................................
     //Выключить звук "Будильника"
     if (Device_IdCommand == DevCom_is_alarm_sound_disable) { alarm_sound_yes = false; LED_state_Actual(); } 
     //.................................
     //.................................
     if (Device_IdCommand == DevCom_is_time_blink_enable_disable)
     { 
         //Включить/выключить "мигание" двоеточия на дисплее
         time_delim_blink = !time_delim_blink; //Инвертировать значение
         Time_View(); //Визуализировать текущее время
         LED_state_Actual(); //Актуальное состояние светодиодов
     } 
     //.................................
     //--------------------------------     
     //--------------------------------     
     //Сбросить код текущей команды Устройства
     Device_IdCommand = DevCom_is_None;
     Device_IdCommand_old = Device_IdCommand;
     //--------------------------------     
     //===================================
     //"Часы"
     //--------------------------------     
     NOW_Get(); //Прочитать текущие Дату и Время из ZS-042
     //--------------------------------     
     //--------------------------------     
     //Если значение "минуты" в ZS-042 изменились,
     //то отображаем новое время на Дисплее
     if (MiOld != Mi)
     {
        MiOld = Mi;
        SeOld = Se;
        time_delim_blink_trig = true;
        //...................
        Time_View(); //Визуализировать текущее время
        //...................
        //.................................
        alarm_action(); //Проверить: не должен ли сработать будильник?
                        //И если "да", то "просигнаить" 
        //...................
     }
     //--------------------------------     
     //--------------------------------     
     //Если значение "секунды" в ZS-042 изменились...
     if (SeOld != Se)
     {
        SeOld = Se;
        //...................
        if (time_delim_blink == true)
        {
           //"Мигание" "двоеточием", если разрешено
           time_delim_blink_trig = ! time_delim_blink_trig; //инверсия значения для визуализации "Двоеточия"
           Time_View(); //Визуализировать текущее время
        }
        //...................
     }  //SeOld != Se
     //--------------------------------     
  }  //Mode_Is_Work == true
  else  //Mode_Is_Work == false
  {
     //--------------------------------     
     if (Device_IdCommand == DevCom_is_alarm_view) 
     {
        //Визуализировать время (ЧЧ:ММ") "Будильника"
        Alarm_View(); //Визуализация времени "Будильника"
     } 
     //--------------------------------     
     else
     //--------------------------------     
     {  //Режим "Настройка"
        LED_state_Actual();  //Актуальное состояние светодиодов
        //...................
        //Выбор объекта настройки: "Часы" или "Будильник"
        Device_IdCommand_buf = obj_set_sel(); //выбор объекта
        //...................
        //...................
        if (Device_IdCommand_buf > 0)
        {
           //Объект выбран
           Device_IdCommand = Device_IdCommand_buf;
           Device_IdCommand_old = Device_IdCommand;
        }
        //...................
        else
        //...................
        {
           //Отказ от ыбора объекта (по кнопке Exit ТВ-пульта)
           Device_IdCommand = DevCom_is_None;
           Device_IdCommand_old = Device_IdCommand;
           Mode_Is_Work = true; //Возврат в режим "Часы"
        }
        //...................
   
        //...................
        if (Device_IdCommand == DevCom_is_Set_Time) 
        {
            //Выбран объект "Часы"
            Clock_Set(); //Интерактивный ввод ЧЧ:ММ с ТВ-пульта для "Часов"
        }
        //...................
        else
        //...................
        {
           if (Device_IdCommand == DevCom_is_Set_Alarm) 
           {
              //Выбран объект "Будильник"
              Alarm_Set(); //Интерактивный ввод ЧЧ:ММ с ТВ-пульта для "Будильника"
           }
        }
        //...................
     }
     //--------------------------------     
     //--------------------------------     
     //Сбросить код текущей команды Устройства и возврат в режим "Часы".
     Device_IdCommand = DevCom_is_None;
     Device_IdCommand_old = Device_IdCommand;
     Mode_Is_Work = true; //Возврат в режим "Часы".
     //--------------------------------     
     //--------------------------------     
     LED_state_Actual();  //Актуальное состояние светодиодов
     //--------------------------------     
  }  //Mode_Is_Work == false
  //========================
}  //loop()


void LED_state_Actual()
{ //Актуальное состояние светодиодов
  digitalWrite(alarm_LED, LOW);
  digitalWrite(alarm_yes_LED, LOW);
  digitalWrite(alarm_sound_yes_LED, LOW);
  digitalWrite(MODE_set_LED, LOW);
  digitalWrite(TIME_set_LED, LOW);
  if (Mode_Is_Work == true)
  {
     if (alarm_yes == true) //будильник включен
     { 
        digitalWrite(alarm_yes_LED, HIGH); 
        if (alarm_sound_yes == true)  //звук будильника разрешен
        { 
           digitalWrite(alarm_sound_yes_LED, HIGH); 
           digitalWrite(alarm_yes_LED, LOW); 
        }
        else  //звук будильника запрещен
        {
           digitalWrite(alarm_sound_yes_LED, LOW);
        }
     }
  }
  else  //будильник вЫключен
  {
     digitalWrite(MODE_set_LED, HIGH);
  }
}  //LED_state_Actual()

void device_test()
{ //"Тест" устройства
  //----------------------------
  digitalWrite(alarm_LED, LOW);
  digitalWrite(alarm_yes_LED, LOW);
  digitalWrite(alarm_sound_yes_LED, LOW);
  digitalWrite(MODE_set_LED, LOW);
  digitalWrite(TIME_set_LED, LOW);
  //----------------------------
  //----------------------------
  digitalWrite(MODE_set_LED, HIGH);
  NumTab[3]= -1; 
  NumTab[2]= -1; 
  NumTab[1]= -1; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(alarm_sound_yes_LED, HIGH);
  NumTab[3]= -1; 
  NumTab[2]= -1; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(alarm_LED, HIGH);
  NumTab[3]= -1; 
  NumTab[2]= 0; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(alarm_yes_LED, HIGH);
  NumTab[3]= 0; 
  NumTab[2]= 0; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(TIME_set_LED, HIGH);
  NumTab[3]= 0; 
  NumTab[2]= 0; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  //----------------------------
  //----------------------------
  analogWrite(alarm_Buzzer, 262); // включаем зуммер (нота ДО 1-й октавы)
  delay(1000);
  analogWrite(alarm_Buzzer, 0); // выключаем зуммер
  //----------------------------
  //----------------------------
  digitalWrite(TIME_set_LED, LOW);
  NumTab[3]= 0; 
  NumTab[2]= 0; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(alarm_yes_LED, LOW);
  NumTab[3]= 0; 
  NumTab[2]= 0; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(alarm_LED, LOW);
  NumTab[3]= -1; 
  NumTab[2]= 0; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(alarm_sound_yes_LED, LOW);
  NumTab[3]= -1; 
  NumTab[2]= -1; 
  NumTab[1]= 0; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  digitalWrite(MODE_set_LED, LOW);
  NumTab[3]= -1; 
  NumTab[2]= -1; 
  NumTab[1]= -1; 
  NumTab[0]= 0; 
  tm1637.point(false); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  delay(200);
  //----------------------------
  //----------------------------
  Time_View(); //Визуализировать текущее время
  //----------------------------
}  //device_test()

void alarm_action()
{  //Действия, связанные с будильником
   if (alarm_yes == true)  //будильник разрешен
   {
      if (alarm_Ho == Ho)
      {
         if (alarm_Mi == Mi)
         {
            //будильник должен сработать
            tm1637.point(true); //Включить двоеточие на 3642BH
            tm1637.display(NumTab); //Вывод массива на дисплей
            digitalWrite(alarm_LED, HIGH);
            if (alarm_sound_yes == true) //звук будильника разрешен
            {
               for (int i=1;i<(alarm_count+1);i++)
               {  
                  digitalWrite(alarm_LED, HIGH);
                  analogWrite(alarm_Buzzer, 262); // включить звук (нота ДО 1-й октавы)
                  delay(alarm_Len);
                  analogWrite(alarm_Buzzer, 0);  // вЫключить звук
                  digitalWrite(alarm_LED, LOW);
                  delay(alarm_Len);
               }
            }
            else  //звук будильника запрещен
            {
               digitalWrite(alarm_LED, HIGH); 
               delay(alarm_count*alarm_Len);
            }
            digitalWrite(alarm_LED, LOW);
            analogWrite(alarm_Buzzer, 0);  // вЫключить звук
            tm1637.point(true); //Включить двоеточие на 3642BH
            tm1637.display(NumTab); //Вывод массива на дисплей

            LED_state_Actual(); //Актуальное состояние светодиодов

         }
      }
   }
}  //alarm_action()


void NOW_Get()
{  //Получить текущие время и дату
  Ye = Clock.getYear();
  Mo = Clock.getMonth(Century);
  Da = Clock.getDate();
  DoW = Clock.getDoW();
  Ho = Clock.getHour(h12, PM);
  Mi = Clock.getMinute();
  Se = Clock.getSecond();
}  //NOW_Get()

void  Time_View()
{ //Визуализация ЧЧ:ММ часов
  //...........................
  int n1 = 0;
  int n2 = 0;
  int n3 = 0;
  int n4 = 0;
  double x = 0.0;
  //...........................
  //...........................
  int HoZ = Ho;
  int MiZ = Mi;
  //...........................
  //...........................
  if (MiZ < 0) { MiZ = 0; }
  if (MiZ > 59) { MiZ = 59; }
  if (HoZ < 0) { HoZ = 0; }
  if (HoZ > 23) { HoZ = 23; }
  //...........................
  //=======================
  //Конвертация
  //...........................
  //"часы"
  x = HoZ/10;
  n1 = floor(x); //десятки часов
  n2 = (HoZ - n1*10); //единицы часов
  //...........................
  //...........................
  //"минуты"
  x = MiZ/10;
  n3 = floor(x); //десятки минут
  n4 = (MiZ - n3*10); //единицы минут
  //...........................
  //=======================
  //...........................
  NumTab[3]=n4; //единицы минут
  NumTab[2]=n3; //десятки минут
  NumTab[1]=n2; //единицы часов
  NumTab[0]=n1; //десятки часов
  //...........................
  //...........................
  if (time_delim_blink == true)
  {
      tm1637.point(time_delim_blink_trig); //Включить/вЫключить двоеточие на 3642BH
  }
  else 
  {
      tm1637.point(true); //Включить двоеточие на 3642BH
  }
  tm1637.display(NumTab); //Вывод массива на дисплей
  //...........................
} //Time_View()

void  Alarm_View()
{ //Визуализация ЧЧ:ММ будильника
  //...........................
  //"Заостряем" внимание Пользователя
  digitalWrite(alarm_yes_LED, HIGH);
  delay(200);
  //...........................
  //...........................
  int n1 = 0;
  int n2 = 0;
  int n3 = 0;
  int n4 = 0;
  double x = 0.0;
  //...........................
  //...........................
  int HoZ = alarm_Ho;
  int MiZ = alarm_Mi;
  //...........................
  //...........................
  if (MiZ < 0) { MiZ = 0; }
  if (MiZ > 59) { MiZ = 59; }
  if (HoZ < 0) { HoZ = 0; }
  if (HoZ > 23) { HoZ = 23; }
  //...........................
  //=======================
  //Конвертация
  //...........................
  //"часы"
  x = HoZ/10;
  n1 = floor(x); //десятки часов
  n2 = (HoZ - n1*10); //единицы часов
  //...........................
  //...........................
  //"минуты"
  x = MiZ/10;
  n3 = floor(x); //десятки минут
  n4 = (MiZ - n3*10); //единицы минут
  //...........................
  //=======================
  //...........................
  NumTab[3]=n4; //единицы минут
  NumTab[2]=n3; //десятки минут
  NumTab[1]=n2; //единицы часов
  NumTab[0]=n1; //десятки часов
  //...........................
  //...........................
  tm1637.point(true); //Включить двоеточие на 3642BH
  tm1637.display(NumTab); //Вывод массива на дисплей
  //...........................
  //...........................
  //"Заостряем" внимание Пользователя
  digitalWrite(alarm_yes_LED, LOW);
  delay(200);
  digitalWrite(alarm_yes_LED, HIGH);
  delay(200);
  digitalWrite(alarm_yes_LED, LOW);
  delay(200);
  digitalWrite(alarm_yes_LED, HIGH);
  //...........................
  delay(2000); //Показываем 2 секунды
  LED_state_Actual(); //Актуальное состояние светодиодов
} //Alarm_View()

int ir_res_to_id(decode_results res)
{ //Приведение "нюансов" ТВ-пультов к "общему знаменателю"
  //Т.е., унификация кодов кнопок ТВ-пультов.
  //Если планируется ипспользовать другие пульты, 
  //то добавить "расшифровку" кодов их кнопок нужно здесь
  int id_com = ky022_id_com_is_unknown;
  //*****************************************************
  // Пульт 'TELEFUNKEN'
  if (results.value == 16679039) { id_com=ky022_id_com_is_1; }
  if (results.value == 16662719) { id_com=ky022_id_com_is_2; }
  if (results.value == 16695359) { id_com=ky022_id_com_is_3; }
  if (results.value == 16654559) { id_com=ky022_id_com_is_4; }
  if (results.value == 16687199) { id_com=ky022_id_com_is_5; }
  if (results.value == 16670879) { id_com=ky022_id_com_is_6; }
  if (results.value == 16703519) { id_com=ky022_id_com_is_7; }
  if (results.value == 16650479) { id_com=ky022_id_com_is_8; }
  if (results.value == 16683119) { id_com=ky022_id_com_is_9; }
  if (results.value == 16646399) { id_com=ky022_id_com_is_0; }
  if (results.value == 16658639) { id_com=ky022_id_com_is_up; }
  if (results.value == 16707599) { id_com=ky022_id_com_is_left; }
  if (results.value == 16674959) { id_com=ky022_id_com_is_right; }
  if (results.value == 16691279)  { id_com=ky022_id_com_is_down; }
  if (results.value == 16648439) { id_com=ky022_id_com_is_enter; }
  if (results.value == 16697399) { id_com=ky022_id_com_is_exit; }
  if (results.value == 16701479) { id_com=ky022_id_com_is_vol_plus; }
  if (results.value == 16668839) { id_com=ky022_id_com_is_vol_minus; }
  if (results.value == 16685159) { id_com=ky022_id_com_is_ch_plus; }
  if (results.value == 16652519) { id_com=ky022_id_com_is_ch_minus; }
  if (results.value == 16697909) { id_com=ky022_id_com_is_btn_red; }
  if (results.value == 16665269) { id_com=ky022_id_com_is_btn_green; }
  if (results.value == 16681589) { id_com=ky022_id_com_is_btn_yellow; }
  if (results.value == 16648949) { id_com=ky022_id_com_is_btn_blue; }
  if (results.value == 4294967295) { id_com=ky022_id_com_is_repeat; }
  //*****************************************************
  //*****************************************************
  // Пульт 'LG'
  if (results.value == 551520375) { id_com=ky022_id_com_is_1; }
  if (results.value == 551504055) { id_com=ky022_id_com_is_2; }
  if (results.value == 551536695) { id_com=ky022_id_com_is_3; }
  if (results.value == 551495895) { id_com=ky022_id_com_is_4; }
  if (results.value == 551528535) { id_com=ky022_id_com_is_5; }
  if (results.value == 551512215) { id_com=ky022_id_com_is_6; }
  if (results.value == 551544855) { id_com=ky022_id_com_is_7; }
  if (results.value == 551491815) { id_com=ky022_id_com_is_8; }
  if (results.value == 551524455) { id_com=ky022_id_com_is_9; }
  if (results.value == 551487735) { id_com=ky022_id_com_is_0; }
  if (results.value == 551486205) { id_com=ky022_id_com_is_up; }
  if (results.value == 551542815) { id_com=ky022_id_com_is_left; }
  if (results.value == 551510175) { id_com=ky022_id_com_is_right; }
  if (results.value == 551518845) { id_com=ky022_id_com_is_down; }
  if (results.value == 551494365) { id_com=ky022_id_com_is_ok; }
  if (results.value == 551541285) { id_com=ky022_id_com_is_exit; }
  if (results.value == 551502015) { id_com=ky022_id_com_is_vol_plus; }
  if (results.value == 551534655) { id_com=ky022_id_com_is_vol_minus; }
  if (results.value == 551485695) { id_com=ky022_id_com_is_ch_plus; }
  if (results.value == 551518335) { id_com=ky022_id_com_is_ch_minus; }
  if (results.value == 551505585) { id_com=ky022_id_com_is_btn_red; }
  if (results.value == 551521905) { id_com=ky022_id_com_is_btn_green; }
  if (results.value == 551536185) { id_com=ky022_id_com_is_btn_yellow; }
  if (results.value == 551519865) { id_com=ky022_id_com_is_btn_blue; }
  if (results.value == 4294967295) { id_com=ky022_id_com_is_repeat; }
  //*****************************************************
  return id_com;
}  //ir_res_to_id

int irrecv_comm_get()
{ //Получение кода нажатой на ТВ-пульте кнопки
  int res = ky022_id_com_is_unknown;
  if ( irrecv.decode( &results ))  // если данные от ТВ-пульта пришли
  {
    res = ir_res_to_id( results ); //Унификация кода кнопки от ТВ-пультов
    if (res != ky022_id_com_is_unknown)
    {
       if (res != ky022_id_com_is_repeat)
       {
          //Здесь код, если потребуется отладка через Serial
       }
       else
       {
          res = ky022_id_com_is_unknown;
       }
    }
    irrecv.resume(); // прием следующей команды от ТВ-пульта
  }
  return res;
}  //irrecv_comm_get

byte device_comm_get(int idcom)
{ //Конвертация кода нажатой на ТВ-пульте кнопки в код команды Устройства
  byte res = Device_IdCommand;
  //-------------
  if (idcom == ky022_id_com_is_btn_red) { res = DevCom_is_Work; }
  if (idcom == ky022_id_com_is_btn_green) { res = DevCom_is_Set; }
  if (idcom == ky022_id_com_is_btn_yellow) { res = DevCom_is_alarm_view; }
  if (idcom == ky022_id_com_is_btn_blue) { res = DevCom_is_time_blink_enable_disable; }
  if (idcom == ky022_id_com_is_ch_plus) { res = DevCom_is_alarm_enable; }
  if (idcom == ky022_id_com_is_ch_minus) { res = DevCom_is_alarm_disable; }
  if (idcom == ky022_id_com_is_vol_plus) { res = DevCom_is_alarm_sound_enable; }
  if (idcom == ky022_id_com_is_vol_minus) { res = DevCom_is_alarm_sound_disable; }
  //-------------
  return res;
}  //device_comm_get()


int obj_set_sel()
{ //Выбор "объекта" установки значений ЧЧ:ММ.
  //Это могут быть часы или будильник
  int res = -1;
  int irkey = 0;
  //-------------------------------------------
  //Сигнализация Пользователю, что от него требуется выбор
  digitalWrite(alarm_LED, HIGH);
  digitalWrite(alarm_yes_LED, HIGH);
  digitalWrite(alarm_sound_yes_LED, HIGH);
  digitalWrite(MODE_set_LED, HIGH);
  digitalWrite(TIME_set_LED, HIGH);
  delay(500);
  digitalWrite(MODE_set_LED, LOW);
  digitalWrite(alarm_LED, LOW);
  digitalWrite(alarm_yes_LED, LOW);
  digitalWrite(alarm_sound_yes_LED, LOW);
  digitalWrite(TIME_set_LED, LOW);
  //-------------------------------------------
  //-------------------------------------------
  digitalWrite(MODE_set_LED, HIGH); //Включение светодиода (зеленого): режим настройки
  //-------------------------------------------
  
  //-------------------------------------------
  bool YesExit = false;
  while (YesExit == false) //цикл ожидания выбора Пользователя
  {
    irkey = irrecv_comm_get();//Получить "нажатую" кнопку на ТВ-пульте
    
    if ((irkey == ky022_id_com_is_up) || (irkey == ky022_id_com_is_left) || 
       (irkey == ky022_id_com_is_down) || (irkey == ky022_id_com_is_right) ||
       (irkey == ky022_id_com_is_enter) || (irkey == ky022_id_com_is_ok) ||
       (irkey == ky022_id_com_is_exit))
    { 
      //----------------------
      //Выбор Пользователя
      if ((irkey == ky022_id_com_is_up) || (irkey == ky022_id_com_is_left) || (irkey == ky022_id_com_is_down) || (irkey == ky022_id_com_is_right))
      {
         if (res == DevCom_is_None)     //Предыдущий выбор - неопределен
         { 
            res = DevCom_is_Set_Time;  //Значит, принудительно: часы
            digitalWrite(TIME_set_LED, HIGH);
            digitalWrite(alarm_yes_LED, LOW);
         }
         else
         {
            if (res == DevCom_is_Set_Time) //Предыдущий выбор был - часы
            { 
               res = DevCom_is_Set_Alarm;  //Значит, "сейчас" будет будильник
               digitalWrite(TIME_set_LED, LOW);
               digitalWrite(alarm_yes_LED, HIGH);
            }
            else  //Если "был" будильник, то теперь - часы
            {
               res = DevCom_is_Set_Time;  //Часы
               digitalWrite(TIME_set_LED, HIGH);
               digitalWrite(alarm_yes_LED, LOW);
            }
         }
      }
      //----------------------
      //----------------------
      //Подтверждение выбора Пользователя или отказ от настройки
      if (irkey == ky022_id_com_is_ok) { YesExit = true; }     //Выбор сделан
      if (irkey == ky022_id_com_is_enter) { YesExit = true; } //Выбор сделан
      if (irkey == ky022_id_com_is_exit) { res = -1; YesExit = true; } //отказ от настройки
      //----------------------
    }
  }  //while end
  //-------------------------------------------
  return res;
}  //obj_set_sel()

byte digit_input(byte nMax, byte nWhere)
{ //Ввести значение ЦИФРЫ с ТВ-пульта
  byte res = 99;
  int irkey = 0;
  bool Yes = false;
  bool YesExit = false;
  while (YesExit == false)  //цикл ожидания нажатия соответствующей кнопки на ТВ-пульте
  {
     irkey = irrecv_comm_get(); //Получить "нажатую" кнопку на ТВ-пульте
     //-------------------------------------------
     //Реагировать только на цифровые кнопки
     Yes = false;
     if (irkey == ky022_id_com_is_0) { res = 0; Yes = true; }
     if (irkey == ky022_id_com_is_1) { res = 1; Yes = true; }
     if (irkey == ky022_id_com_is_2) { res = 2; Yes = true; }
     if (irkey == ky022_id_com_is_3) { res = 3; Yes = true; }
     if (irkey == ky022_id_com_is_4) { res = 4; Yes = true; }
     if (irkey == ky022_id_com_is_5) { res = 5; Yes = true; }
     if (irkey == ky022_id_com_is_6) { res = 6; Yes = true; }
     if (irkey == ky022_id_com_is_7) { res = 7; Yes = true; }
     if (irkey == ky022_id_com_is_8) { res = 8; Yes = true; }
     if (irkey == ky022_id_com_is_9) { res = 9; Yes = true; }
     //-------------------------------------------
     //-------------------------------------------
     if (Yes == true)
     {
        //Визуализировать "нажатую" на ТВ-пульте цифру в заданном разряде 3642BH
        NumTab[nWhere]=res; 
        tm1637.display(NumTab); //Вывод массива на дисплей
     }
     //-------------------------------------------
     //-------------------------------------------
     if (res <= nMax) //Введенная с ТВ-пульта цифра - в заданных пределах
     {
        //Выход из цикла ввода цифры с ТВ-пульта
        if (irkey == ky022_id_com_is_ok) { YesExit = true; }
        if (irkey == ky022_id_com_is_enter) { YesExit = true; }
     }
     //-------------------------------------------
  }  //while end
  return res; 
}  //digit_input()

void HH_Set(bool ItsClock)
{ //Ввести интерактивно значения ЧЧ с ТВ-пульта
  bool YesExit = false;
  int h99 = 0;  //часы
  while (YesExit == false)  //Цикл ввода значения ЧЧ
  {
     //...........................
     NumTab[3]=-1; //единицы минут
     NumTab[2]=-1; //десятки минут
     NumTab[1]=-1; //единицы часов
     NumTab[0]= 15; //десятки часов
     tm1637.point(false); //Включить двоеточие на 3642BH
     tm1637.display(NumTab); //Вывод массива на дисплей
     //...........................
     //...........................
     byte h1 = digit_input(2, 0); //десятки часов
     NumTab[1]=15; //единицы часов
     NumTab[0]=h1; //десятки часов
     tm1637.point(true); //Включить двоеточие на 3642BH
     tm1637.display(NumTab); //Вывод массива на дисплей
     //...........................
     //...........................
     byte h2 = digit_input(9, 1); //единицы часов
     NumTab[1]=h2; //единицы часов
     tm1637.point(true); //Включить двоеточие на 3642BH
     tm1637.display(NumTab); //Вывод массива на дисплей
     //...........................
     //...........................
     h99 = h1*10 + h2;
     if (h99 < 24) 
     {  //Допустимое значение
        YesExit = true; 
     }
     else
     {  //Ошибочное значение
        digitalWrite(alarm_LED, HIGH);
        analogWrite(alarm_Buzzer, 1046); // включаем зуммер (нота ДО 3-й октавы)
        delay(500);
        analogWrite(alarm_Buzzer, 0); // выключаем зуммер
        digitalWrite(alarm_LED, LOW);
     }
     //...........................
  } //while end
  //...........................
  if (ItsClock == true)
  {  //Установить значение ЧЧ часов
     Clock.setHour(h99);
  }
  else 
  {  //Установить значение ЧЧ будильника
     alarm_Ho = h99;       
  }
  //...........................
}  //HH_Set()


void MM_Set(bool ItsClock)
{ //Ввести интерактивно значения ММ с ТВ-пульта 
  bool YesExit = false;
  int m99 = 0;  //Минуты
  while (YesExit == false)  //Цикл ввода значения ММ
  {
     //...........................
     NumTab[3]=-1; //единицы минут
     NumTab[2]=15; //десятки минут
     //NumTab[1]=-1; //единицы часов
     //NumTab[0]= 0; //десятки часов
     tm1637.point(true); //Включить двоеточие на 3642BH
     tm1637.display(NumTab); //Вывод массива на дисплей
     //...........................
     //...........................
     byte m1 = digit_input(5, 2); //десятки минут
     NumTab[3]=15; //единицы минут
     NumTab[2]=m1; //десятки минут
     tm1637.point(true); //Включить двоеточие на 3642BH
     tm1637.display(NumTab); //Вывод массива на дисплей
     //...........................
     //...........................
     byte m2 = digit_input(9, 3); //единицы минут
     NumTab[3]=m2; //единицы часов
     tm1637.point(true); //Включить двоеточие на 3642BH
     tm1637.display(NumTab); //Вывод массива на дисплей
     //...........................
     //...........................
     m99 = m1*10 + m2;
     if (m99 < 60) 
     {  //Допустимое значение
        YesExit = true; 
     }
     else
     {  //Ошибочное значение
        digitalWrite(alarm_LED, HIGH);
        analogWrite(alarm_Buzzer, 1046); // включаем зуммер (нота ДО 3-й октавы)
        delay(500);
        analogWrite(alarm_Buzzer, 0); // выключаем зуммер
        digitalWrite(alarm_LED, LOW);
     }
     //...........................
  } //while end
  //...........................
  if (ItsClock == true)
  {  //Установить значение ММ часов
     Clock.setMinute(m99);
     Clock.setSecond(0);
  }
  else 
  {  //Установить значение ММ будильника
    alarm_Mi = m99;       
  }
  //...........................
} //MM_Set()

void Clock_Set()
{ //Установить значение ЧЧ:ММ часов
   //-------------------------
   HH_Set(true); //установить часы
   MM_Set(true); //установить минуты
   //-------------------------
}  //Clock_Set()

void Alarm_Set()
{ //Установить значение ЧЧ:ММ будильника
   //-------------------------
   HH_Set(false); //установить часы
   MM_Set(false); //установить минуты
   //-------------------------
   //-------------------------
   //задержка для визуализации Пользователю
   delay(1000); 
   digitalWrite(alarm_yes_LED, LOW);
   delay(200); 
   digitalWrite(alarm_yes_LED, HIGH);
   delay(200); 
   digitalWrite(alarm_yes_LED, LOW);
   delay(200); 
   digitalWrite(alarm_yes_LED, HIGH);
   delay(1000); 
   //-------------------------
   //-------------------------
   alarm_yes = true;   //Сразу и сам будильник включаем
   LED_state_Actual(); //Актуальное состояние светодиодов 
   //-------------------------
}  //Alarm_Set()

/*  
//====================================
//Функции DateToStr() и TimeToStr() предназначены
//для вывода даты и времени в строковом формате
//на компьютер через Serial.
//Т.е., используются для отладки
String DateToStr()
{
  String S = " ";
  if (Da > 9) { S = S + Da; } else { S = S + "0" + Da; }
  S = S +".";
  if (Mo > 9) { S = S + Mo; } else { S = S + "0" + Mo; }
  S = S +".";
  S = S + (2000 + Ye);
  S.trim();
  return S;
}  //DateToStr()

String TimeToStr(bool itsFull)
{
  String S = " ";
  if (Ho > 9) { S = S + Ho; } else { S = S + "0" + Ho; }
  S = S +":";
  if (Mi > 9) { S = S + Mi; } else { S = S + "0" + Mi; }
  if (itsFull == true)
  {
     S = S +":";
     if (Se > 9) { S = S + Se; } else { S = S + "0" + Se; }
  }
  S.trim();
  return S;
}  //TimeToStr
// ==================================== 
*/