From 53c36f9d0952c14d2b7cb8b14c186f1e46a57c53 Mon Sep 17 00:00:00 2001
From: egorguslyan <egorguslyan@gmail.com>
Date: Tue, 4 Jan 2022 20:50:11 +0300
Subject: [PATCH] RTC, handlers

---
 .gitmodules                                   |   6 +-
 Dashboard/Dashboard.ino                       | 119 ++++++++-
 Dashboard/config.h                            |   7 +-
 Dashboard/screens.h                           |   3 +-
 libraries/microDS3231/LICENSE                 |  21 ++
 libraries/microDS3231/README.md               | 200 +++++++++++++++
 .../examples/DS3231_demo/DS3231_demo.ino      | 101 ++++++++
 .../examples/DateTime/DateTime.ino            |  52 ++++
 libraries/microDS3231/keywords.txt            |  53 ++++
 libraries/microDS3231/library.properties      |   9 +
 libraries/microDS3231/src/buildTime.h         |  83 +++++++
 libraries/microDS3231/src/microDS3231.cpp     | 229 ++++++++++++++++++
 libraries/microDS3231/src/microDS3231.h       |  82 +++++++
 13 files changed, 960 insertions(+), 5 deletions(-)
 create mode 100644 libraries/microDS3231/LICENSE
 create mode 100644 libraries/microDS3231/README.md
 create mode 100644 libraries/microDS3231/examples/DS3231_demo/DS3231_demo.ino
 create mode 100644 libraries/microDS3231/examples/DateTime/DateTime.ino
 create mode 100644 libraries/microDS3231/keywords.txt
 create mode 100644 libraries/microDS3231/library.properties
 create mode 100644 libraries/microDS3231/src/buildTime.h
 create mode 100644 libraries/microDS3231/src/microDS3231.cpp
 create mode 100644 libraries/microDS3231/src/microDS3231.h

diff --git a/.gitmodules b/.gitmodules
index ca8da7d..fd553b0 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,4 +4,8 @@
 
 [submodule "mhz19_uart"]
     path = libraries/mhz19_uart
-    url = https://github.com/piot-jp-Team/mhz19_uart
\ No newline at end of file
+    url = https://github.com/piot-jp-Team/mhz19_uart
+
+[submodule "microDS3231"]
+    path = libraries/microDS3231
+    url = https://github.com/GyverLibs/microDS3231
\ No newline at end of file
diff --git a/Dashboard/Dashboard.ino b/Dashboard/Dashboard.ino
index dc95587..8817614 100644
--- a/Dashboard/Dashboard.ino
+++ b/Dashboard/Dashboard.ino
@@ -27,6 +27,10 @@
 #include <MHZ19_uart.h>
 /********************************/
 
+/**********RTC library***********/
+#include <microDS3231.h>
+/********************************/
+
 #include <EEPROM.h>
 
 /*************Marcos*************/
@@ -104,17 +108,92 @@ microLED<NUMLEDS, LEDsPin, MLED_NO_CLOCK, LED_WS2812, ORDER_GRB, CLI_AVER, SAVE_
 textbox tb;
 #include "configScreens.h"
 MHZ19_uart co2;
+MicroDS3231 rtc;
 
-extern volatile unsigned long timer0_millis;
+extern volatile uint32_t timer0_overflow_count;
+extern volatile uint32_t timer0_millis;
+
+// Spaghetti
+void buttons()
+{
+  static uint32_t timer2_btnl = 0;
+  static uint32_t timer2_btnr = 0;
+  static uint8_t btn_flags = 0;
+  if(digitalRead(LBTN) || bitRead(btn_flags, 0)) 
+  {
+    if(bitRead(btn_flags, 1))
+    {
+      if(!bitRead(btn_flags, 0))
+      {
+        bitWrite(btn_flags, 0, 1);
+        timer2_btnl = millis();
+      }
+      if((millis() - timer2_btnl <= BOTH_DELAY) && digitalRead(RBTN))
+        bitWrite(btn_flags, 1, 1);
+      else if((millis() - timer2_btnl <= SWIPE_DELAY) && digitalRead(RBTN))
+      {
+        globalVars.swipeRight = 1;
+        bitWrite(btn_flags, 1, 1);
+      }
+      else if(digitalRead(RBTN))
+        bitWrite(btn_flags, 1, 1);
+      else if(!(millis() - timer2_btnl <= SWIPE_DELAY) && !digitalRead(LBTN))
+      {
+        globalVars.tapLeft = 1;
+        bitWrite(btn_flags, 1, 1);
+      }
+      else if(millis() - timer2_btnl > HOLD_DELAY)
+      {
+        globalVars.holdLeft = 1;
+        bitWrite(btn_flags, 1, 1);
+      }
+    }
+    else if(!digitalRead(LBTN) && !digitalRead(RBTN)) btn_flags = 0;
+  }
+  else if(digitalRead(RBTN) || bitRead(btn_flags, 0)) 
+  {
+    if(bitRead(btn_flags, 1))
+    {
+      if(!bitRead(btn_flags, 0))
+      {
+        bitWrite(btn_flags, 0, 1);
+        timer2_btnl = millis();
+      }
+      if((millis() - timer2_btnl <= BOTH_DELAY) && digitalRead(LBTN))
+        bitWrite(btn_flags, 1, 1);
+      else if((millis() - timer2_btnl <= SWIPE_DELAY) && digitalRead(LBTN))
+      {
+        globalVars.swipeLeft = 1;
+        bitWrite(btn_flags, 1, 1);
+      }
+      else if(digitalRead(LBTN))
+        bitWrite(btn_flags, 1, 1);
+      else if(!(millis() - timer2_btnl <= SWIPE_DELAY) && !digitalRead(RBTN))
+      {
+        globalVars.tapRight = 1;
+        bitWrite(btn_flags, 1, 1);
+      }
+      else if(millis() - timer2_btnl > HOLD_DELAY)
+      {
+        globalVars.holdRight = 1;
+        bitWrite(btn_flags, 1, 1);
+      }
+    }
+    else if(!digitalRead(LBTN) && !digitalRead(RBTN)) btn_flags = 0;
+  }
+}
 
 void setup()
 {
   // Hardware init
+  pinMode(LBTN, INPUT);
+  pinMode(RBTN, INPUT);
   matrix.setBrightness(100);
   matrix.clear();
   matrix.show();
   co2.begin(CO2TX, CO2RX);
   co2.setAutoCalibration(false);
+  // Serial transmission
   Serial.begin(9600);
   // For safe debugging
   //while (!Serial.available()) {}
@@ -126,6 +205,12 @@ void setup()
   if((eepromData & 0b11111100 == special_key) && (eepromData & 0b00000011 < 3))
     globalVars.panelOrientation = eepromData & 0b00000011;
   else globalVars.panelOrientation = PANEL_UNKNOWN;
+  eepromData = EEPROM.read(1);
+  if(!(eepromData == special_key))
+  {
+    EEPROM.write(1, special_key);
+    rtc.setTime(COMPILE_TIME);
+  }
 
   // Set start screen
   globalVars.currentScreen = startWith;
@@ -152,6 +237,33 @@ void loop()
     Serial.end();
   }
 
+  // Measure CO2 every 5 seconds
+  static uint32_t timer0 = 0;
+  TIMER(timer0, 5000)
+  {
+    globalVars.ppm = co2.getPPM();
+  }
+
+  // Update time every second
+  static uint32_t timer1 = 0;
+  static DateTime DTtmp;
+  TIMER(timer1, 999)
+  {
+    globalVars.hours = DTtmp.hour;
+    globalVars.minutes = DTtmp.minute;
+    if(globalVars.seconds != DTtmp.second)
+      DTtmp = rtc.getTime();
+    globalVars.seconds = DTtmp.second;
+  }
+
+  // Detect taps and swipes
+  static uint32_t timer2 = 0;
+  TIMER(timer2, 10)
+  {
+    buttons();
+  }
+
+  // Display
   switch(globalVars.prepare)
   {
     case 1:
@@ -163,7 +275,6 @@ void loop()
       screens[globalVars.currentScreen].func(&screens[globalVars.currentScreen].arg);
     break;
   }
-
   matrix.show();
 
   // Monthly preventative safe reset of the millis() timer
@@ -171,9 +282,13 @@ void loop()
   {
     noInterrupts();
       timer0_millis = 0;
+      timer0_overflow_count = 0;
     interrupts();
     globalVars.timer = 0;
     tb.resetTimers();
     timer_debug0 = 0;
+    timer0 = 0;
+    timer1 = 0;
+    timer2 = 0;
   }
 }
\ No newline at end of file
diff --git a/Dashboard/config.h b/Dashboard/config.h
index f8ffa54..99a356e 100644
--- a/Dashboard/config.h
+++ b/Dashboard/config.h
@@ -9,4 +9,9 @@
 #define HEIGHT 9
 
 #define COLOR1 mHEX(0x9aa100)
-#define COLOR2 mHEX(0x000aa0)
\ No newline at end of file
+#define COLOR2 mHEX(0x000aa0)
+
+// Delay between button fronts _|¯ have to be greater than BOTH_DELAY and less than SWIPE_DELAY
+#define BOTH_DELAY 30
+#define SWIPE_DELAY 700
+#define HOLD_DELAY 2000
\ No newline at end of file
diff --git a/Dashboard/screens.h b/Dashboard/screens.h
index 76eea57..5a8fc4f 100644
--- a/Dashboard/screens.h
+++ b/Dashboard/screens.h
@@ -97,7 +97,8 @@ void welcome(Arg *arg)
 
 void welcomePrepare()
 {
-    memset(globalVars.leds, mBlack, sizeof(mData) * NUMLEDS);
+    //memset(globalVars.leds, mBlack, sizeof(mData) * NUMLEDS);
+    return;
 }
 
 void dashboard(Arg *arg)
diff --git a/libraries/microDS3231/LICENSE b/libraries/microDS3231/LICENSE
new file mode 100644
index 0000000..353b7ee
--- /dev/null
+++ b/libraries/microDS3231/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Alex
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/libraries/microDS3231/README.md b/libraries/microDS3231/README.md
new file mode 100644
index 0000000..781256f
--- /dev/null
+++ b/libraries/microDS3231/README.md
@@ -0,0 +1,200 @@
+![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)
+![author](https://img.shields.io/badge/author-AlexGyver-informational.svg)
+# microDS3231
+Лёгкая библиотека для работы с RTC DS3231 для Arduino
+- Чтение и запись времени
+- Вывод в char* и String
+- Чтение температуры датчика
+
+### Совместимость
+Совместима со всеми Arduino платформами (используются Arduino-функции)
+
+## Содержание
+- [Установка](#install)
+- [Инициализация](#init)
+- [Использование](#usage)
+- [Пример](#example)
+- [Версии](#versions)
+- [Баги и обратная связь](#feedback)
+
+<a id="install"></a>
+## Установка
+- Библиотеку можно найти по названию **microDS3231** и установить через менеджер библиотек в:
+    - Arduino IDE
+    - Arduino IDE v2
+    - PlatformIO
+- [Скачать библиотеку](https://github.com/GyverLibs/microDS3231/archive/refs/heads/main.zip) .zip архивом для ручной установки:
+    - Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
+    - Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32)
+    - Распаковать и положить в *Документы/Arduino/libraries/*
+    - (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив
+- Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA)
+
+<a id="init"></a>
+## Инициализация
+```cpp
+MicroDS3231 rtc;        // адрес по умолчанию 0x68
+MicroDS3231 rtc(адрес); // указать свой адрес
+```
+
+<a id="usage"></a>
+## Использование
+```cpp
+bool begin();                   // инициализация, вернет true, если RTC найден
+void setTime(uint8_t param);	// установка времени == времени компиляции
+void setTime(DateTime time);	// установить из структуры DateTime
+void setTime(int8_t seconds, int8_t minutes, int8_t hours, int8_t date, int8_t month, int16_t year);	// установка времени
+void setHMSDMY(int8_t hours, int8_t minutes, int8_t seconds, int8_t date, int8_t month, int16_t year);	// установка времени тип 2
+    
+// структура DateTime
+uint8_t second; 
+uint8_t minute;
+uint8_t hour;
+uint8_t day;
+uint8_t date;
+uint8_t month;
+uint16_t year;
+
+DateTime getTime();			// получить в структуру DateTime
+uint8_t getSeconds();		// получить секунды
+uint8_t getMinutes();		// получить минуты
+uint8_t getHours();			// получить часы
+uint8_t getDay();			// получить день недели
+uint8_t getDate();			// получить число
+uint16_t getYear();			// получить год
+uint8_t getMonth();			// получить месяц
+    
+String getTimeString();			// получить время как строку вида HH:MM:SS
+String getDateString();			// получить дату как строку вида DD.MM.YYYY
+void getTimeChar(char* array);	// получить время как char array [8] вида HH:MM:SS
+void getDateChar(char* array);	// получить дату как char array [10] вида DD.MM.YYYY       
+    
+bool lostPower();			// проверка на сброс питания
+float getTemperatureFloat();// получить температуру float
+int getTemperature();		// получить температуру int
+```
+
+<a id="example"></a>
+## Пример
+Остальные примеры смотри в **examples**!
+```cpp
+// демо возможностей библиотеки
+#include <microDS3231.h>
+MicroDS3231 rtc;
+
+void setup() {
+  Serial.begin(9600);
+  
+  // проверка наличия модуля на линии i2c
+  // вызов rtc.begin() не обязателен для работы
+  if (!rtc.begin()) {
+    Serial.println("DS3231 not found");
+    for(;;);
+  }
+  
+  // ======== УСТАНОВКА ВРЕМЕНИ АВТОМАТИЧЕСКИ ========
+  // rtc.setTime(COMPILE_TIME);     // установить время == времени компиляции
+  
+  // визуально громоздкий, но более "лёгкий" с точки зрения памяти способ установить время компиляции
+  rtc.setTime(BUILD_SEC, BUILD_MIN, BUILD_HOUR, BUILD_DAY, BUILD_MONTH, BUILD_YEAR);
+    
+  if (rtc.lostPower()) {            // выполнится при сбросе батарейки
+    Serial.println("lost power!");
+    // тут можно однократно установить время == времени компиляции
+  }
+  
+  // ======== УСТАНОВКА ВРЕМЕНИ ВРУЧНУЮ ========    
+  // установить время вручную можно двумя способами (подставить реальные числа)
+  //rtc.setTime(SEC, MIN, HOUR, DAY, MONTH, YEAR);
+  //rtc.setHMSDMY(HOUR, MIN, SEC, DAY, MONTH, YEAR);
+  
+  // также можно установить время через DateTime
+  /*
+  DateTime now;
+  now.second = 0;
+  now.minute = 10;
+  now.hour = 50;
+  now.date = 2;
+  now.month = 9;
+  now.year = 2021;
+  
+  rtc.setTime(now);  // загружаем в RTC
+  */
+}
+
+void loop() {
+  // получение и вывод каждой компоненты
+  Serial.print(rtc.getHours());
+  Serial.print(":");
+  Serial.print(rtc.getMinutes());
+  Serial.print(":");
+  Serial.print(rtc.getSeconds());
+  Serial.print(" ");
+  Serial.print(rtc.getDay());
+  Serial.print(" ");
+  Serial.print(rtc.getDate());
+  Serial.print("/");
+  Serial.print(rtc.getMonth());
+  Serial.print("/");
+  Serial.println(rtc.getYear());
+  
+  /*
+  // можно через DateTime (более оптимально):
+  DateTime now = rtc.getTime();
+  Serial.print(now.hour);
+  Serial.print(":");
+  Serial.print(now.minute);
+  Serial.print(":");
+  Serial.print(now.second);
+  Serial.print(" ");
+  Serial.print(now.day);
+  Serial.print(" ");
+  Serial.print(now.date);
+  Serial.print("/");
+  Serial.print(now.month);
+  Serial.print("/");
+  Serial.println(now.year);
+  */
+  
+  // вывод температуры чипа
+  Serial.println(rtc.getTemperatureFloat());  
+  //Serial.println(rtc.getTemperature());
+  
+  // вывод времени готовой строкой String
+  Serial.println(rtc.getTimeString());
+  
+  // вывод даты готовой строкой String
+  Serial.println(rtc.getDateString());
+
+  // вывод времени через char array
+  char time[8];
+  rtc.getTimeChar(time);
+  Serial.println(time);
+  
+  // вывод даты через char array
+  char date[10];
+  rtc.getDateChar(date);
+  Serial.println(date);
+  
+  Serial.println();
+  delay(500);
+}
+```
+
+<a id="versions"></a>
+## Версии
+- v1.2 - добавлены ограничения на вводимые в setTime числа. Также нельзя ввести 29 февраля увы =)
+- v1.3 - пофикшено зависание, когда модуль отключен но опрашивается
+- v1.4 - незначительный фикс
+- v2.0 - новые возможности, оптимизация и облегчение
+- v2.1 - добавил вывод температуры, вывод в String и char
+- v2.2 - исправлены дни недели (пн-вс 1-7)
+- v2.3 - небольшие исправления, оптимизация, изменён порядок вывода даты
+- v2.4 - исправлена установка времени компиляции
+- v2.5 - добавлен begin для проверки наличия модуля на линии
+- v2.6 - исправлены отрицательные температуры
+    
+<a id="feedback"></a>
+## Баги и обратная связь
+При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru)  
+Библиотека открыта для доработки и ваших **Pull Request**'ов!
\ No newline at end of file
diff --git a/libraries/microDS3231/examples/DS3231_demo/DS3231_demo.ino b/libraries/microDS3231/examples/DS3231_demo/DS3231_demo.ino
new file mode 100644
index 0000000..95d51e7
--- /dev/null
+++ b/libraries/microDS3231/examples/DS3231_demo/DS3231_demo.ino
@@ -0,0 +1,101 @@
+// демо возможностей библиотеки
+#include <microDS3231.h>
+MicroDS3231 rtc;
+
+void setup() {
+  Serial.begin(9600);
+  
+  // проверка наличия модуля на линии i2c
+  // вызов rtc.begin() не обязателен для работы
+  if (!rtc.begin()) {
+    Serial.println("DS3231 not found");
+    for(;;);
+  }
+  
+  // ======== УСТАНОВКА ВРЕМЕНИ АВТОМАТИЧЕСКИ ========
+  // rtc.setTime(COMPILE_TIME);     // установить время == времени компиляции
+  
+  // визуально громоздкий, но более "лёгкий" с точки зрения памяти способ установить время компиляции
+  rtc.setTime(BUILD_SEC, BUILD_MIN, BUILD_HOUR, BUILD_DAY, BUILD_MONTH, BUILD_YEAR);
+    
+  if (rtc.lostPower()) {            // выполнится при сбросе батарейки
+    Serial.println("lost power!");
+    // тут можно однократно установить время == времени компиляции
+  }
+  
+  // ======== УСТАНОВКА ВРЕМЕНИ ВРУЧНУЮ ========    
+  // установить время вручную можно двумя способами (подставить реальные числа)
+  //rtc.setTime(SEC, MIN, HOUR, DAY, MONTH, YEAR);
+  //rtc.setHMSDMY(HOUR, MIN, SEC, DAY, MONTH, YEAR);
+  
+  // также можно установить время через DateTime
+  /*
+  DateTime now;
+  now.second = 0;
+  now.minute = 10;
+  now.hour = 50;
+  now.date = 2;
+  now.month = 9;
+  now.year = 2021;
+  
+  rtc.setTime(now);  // загружаем в RTC
+  */
+}
+
+void loop() {
+  // получение и вывод каждой компоненты
+  Serial.print(rtc.getHours());
+  Serial.print(":");
+  Serial.print(rtc.getMinutes());
+  Serial.print(":");
+  Serial.print(rtc.getSeconds());
+  Serial.print(" ");
+  Serial.print(rtc.getDay());
+  Serial.print(" ");
+  Serial.print(rtc.getDate());
+  Serial.print("/");
+  Serial.print(rtc.getMonth());
+  Serial.print("/");
+  Serial.println(rtc.getYear());
+  
+  /*
+  // можно через DateTime (более оптимально):
+  DateTime now = rtc.getTime();
+  Serial.print(now.hour);
+  Serial.print(":");
+  Serial.print(now.minute);
+  Serial.print(":");
+  Serial.print(now.second);
+  Serial.print(" ");
+  Serial.print(now.day);
+  Serial.print(" ");
+  Serial.print(now.date);
+  Serial.print("/");
+  Serial.print(now.month);
+  Serial.print("/");
+  Serial.println(now.year);
+  */
+  
+  // вывод температуры чипа
+  Serial.println(rtc.getTemperatureFloat());  
+  //Serial.println(rtc.getTemperature());
+  
+  // вывод времени готовой строкой String
+  Serial.println(rtc.getTimeString());
+  
+  // вывод даты готовой строкой String
+  Serial.println(rtc.getDateString());
+
+  // вывод времени через char array
+  char time[9]; // буфер минимум на 9 символов (8 данные + 1 нулевой)
+  rtc.getTimeChar(time);
+  Serial.println(time);
+  
+  // вывод даты через char array
+  char date[11]; // буфер минимум на 11 символов (10 данные + 1 нулевой)
+  rtc.getDateChar(date);
+  Serial.println(date);
+  
+  Serial.println();
+  delay(500);
+}
diff --git a/libraries/microDS3231/examples/DateTime/DateTime.ino b/libraries/microDS3231/examples/DateTime/DateTime.ino
new file mode 100644
index 0000000..55f8c1e
--- /dev/null
+++ b/libraries/microDS3231/examples/DateTime/DateTime.ino
@@ -0,0 +1,52 @@
+#include <microDS3231.h>
+MicroDS3231 rtc;
+
+void setup() {
+  Serial.begin(9600);
+  
+  // проверка наличия модуля на линии i2c
+  if (!rtc.begin()) {
+    Serial.println("DS3231 not found");
+    for(;;);
+  }
+
+  // получаем все данные в структуру
+  DateTime now = rtc.getTime();
+
+  // меняем любой параметр
+  now.year += 5;
+  // now.second;
+  // now.minute;
+  // now.hour;
+  // now.day;
+  // now.date;
+  // now.month;
+
+  // отправляем в rtc
+  rtc.setTime(now);
+}
+
+void loop() {
+  printTime();
+  delay(500);
+}
+
+void printTime() {
+  // получаем все данные в структуру и используем их
+  // этот способ быстрее и "легче" вызова отдельных get-функций
+  DateTime now = rtc.getTime();
+
+  Serial.print(now.hour);
+  Serial.print(":");
+  Serial.print(now.minute);
+  Serial.print(":");
+  Serial.print(now.second);
+  Serial.print(" ");
+  Serial.print(now.day);
+  Serial.print(" ");
+  Serial.print(now.date);
+  Serial.print("/");
+  Serial.print(now.month);
+  Serial.print("/");
+  Serial.println(now.year);
+}
diff --git a/libraries/microDS3231/keywords.txt b/libraries/microDS3231/keywords.txt
new file mode 100644
index 0000000..299c063
--- /dev/null
+++ b/libraries/microDS3231/keywords.txt
@@ -0,0 +1,53 @@
+  
+#######################################
+# Syntax Coloring Map For microDS3231
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+microDS3231	KEYWORD1
+MicroDS3231	KEYWORD1
+DateTime	KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+begin	KEYWORD2
+setTime	KEYWORD2
+setHMSDMY	KEYWORD2
+getTime	KEYWORD2
+lostPower	KEYWORD2
+getSeconds	KEYWORD2
+getMinutes	KEYWORD2
+getHours	KEYWORD2
+getDay	KEYWORD2
+getDate	KEYWORD2
+getYear	KEYWORD2
+getMonth	KEYWORD2
+getTemperatureFloat	KEYWORD2
+getTemperature	KEYWORD2
+getTimeString	KEYWORD2
+getDateString	KEYWORD2
+getTimeChar	KEYWORD2
+getDateChar	KEYWORD2
+
+second	KEYWORD2
+minute	KEYWORD2
+hour	KEYWORD2
+day	KEYWORD2
+date	KEYWORD2
+month	KEYWORD2
+year	KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+COMPILE_TIME	LITERAL1
+BUILD_SEC	LITERAL1
+BUILD_MIN	LITERAL1
+BUILD_HOUR	LITERAL1
+BUILD_DAY	LITERAL1
+BUILD_MONTH	LITERAL1
+BUILD_YEAR	LITERAL1
\ No newline at end of file
diff --git a/libraries/microDS3231/library.properties b/libraries/microDS3231/library.properties
new file mode 100644
index 0000000..bd028b2
--- /dev/null
+++ b/libraries/microDS3231/library.properties
@@ -0,0 +1,9 @@
+name=microDS3231
+version=2.6
+author=AlexGyver <alex@alexgyver.ru>
+maintainer=AlexGyver <alex@alexgyver.ru>
+sentence=Light library for DS3231 RTC module
+paragraph=Light library for DS3231 RTC module
+category=Device Control
+url=https://github.com/GyverLibs/microDS3231
+architectures=*
\ No newline at end of file
diff --git a/libraries/microDS3231/src/buildTime.h b/libraries/microDS3231/src/buildTime.h
new file mode 100644
index 0000000..9405b22
--- /dev/null
+++ b/libraries/microDS3231/src/buildTime.h
@@ -0,0 +1,83 @@
+/*
+    Парсинг и получение даты и времени компиляции из __DATE__ и __TIME__
+    Документация: 
+    GitHub: https://github.com/GyverLibs/buildTime
+    Константы времени компиляции:
+    BUILD_YEAR	- год
+    BUILD_MONTH	- месяц
+    BUILD_DAY	- день
+    BUILD_HOUR	- час
+    BUILD_MIN	- минута
+    BUILD_SEC	- секунда
+    
+    Исходник http://qaru.site/questions/186859/how-to-use-date-and-time-predefined-macros-in-as-two-integers-then-stringify
+    AlexGyver, alex@alexgyver.ru
+    https://alexgyver.ru/
+    MIT License
+
+    Версии:
+    v1.0 - релиз
+*/
+
+
+#ifndef buildTime_h
+#define buildTime_h
+// Example of __DATE__ string: "Jul 27 2012"
+//                              01234567890
+
+#define BUILD_YEAR_CH0 (__DATE__[7]-'0')
+#define BUILD_YEAR_CH1 (__DATE__[8]-'0')
+#define BUILD_YEAR_CH2 (__DATE__[9]-'0')
+#define BUILD_YEAR_CH3 (__DATE__[10]-'0')
+#define BUILD_YEAR (BUILD_YEAR_CH0*1000+BUILD_YEAR_CH1*100 + BUILD_YEAR_CH2*10+BUILD_YEAR_CH3)
+
+#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
+#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F')
+#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
+#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
+#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
+#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
+#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
+#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
+#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S')
+#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O')
+#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N')
+#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D')
+
+#define BUILD_MONTH \
+    ( \
+    (BUILD_MONTH_IS_JAN) ? 1 : \
+    (BUILD_MONTH_IS_FEB) ? 2 : \
+    (BUILD_MONTH_IS_MAR) ? 3 : \
+    (BUILD_MONTH_IS_APR) ? 4 : \
+    (BUILD_MONTH_IS_MAY) ? 5 : \
+    (BUILD_MONTH_IS_JUN) ? 6 : \
+    (BUILD_MONTH_IS_JUL) ? 7 : \
+    (BUILD_MONTH_IS_AUG) ? 8 : \
+    (BUILD_MONTH_IS_SEP) ? 9 : \
+    (BUILD_MONTH_IS_OCT) ? 10 : \
+    (BUILD_MONTH_IS_NOV) ? 11 : \
+    (BUILD_MONTH_IS_DEC) ? 12 : \
+    /* error default */    '?' \
+    )
+
+#define BUILD_DAY_CH0 (((__DATE__[4] >= '0') ? (__DATE__[4]) : '0')-'0')
+#define BUILD_DAY_CH1 (__DATE__[5]-'0')
+#define BUILD_DAY (BUILD_DAY_CH0*10+BUILD_DAY_CH1)
+
+// Example of __TIME__ string: "21:06:19"
+//                              01234567
+
+#define BUILD_HOUR_CH0 (__TIME__[0]-'0')
+#define BUILD_HOUR_CH1 (__TIME__[1]-'0')
+#define BUILD_HOUR (BUILD_HOUR_CH0*10+BUILD_HOUR_CH1)
+
+#define BUILD_MIN_CH0 (__TIME__[3]-'0')
+#define BUILD_MIN_CH1 (__TIME__[4]-'0')
+#define BUILD_MIN (BUILD_MIN_CH0*10+BUILD_MIN_CH1)
+
+#define BUILD_SEC_CH0 (__TIME__[6]-'0')
+#define BUILD_SEC_CH1 (__TIME__[7]-'0')
+#define BUILD_SEC (BUILD_SEC_CH0*10+BUILD_SEC_CH1)
+
+#endif
\ No newline at end of file
diff --git a/libraries/microDS3231/src/microDS3231.cpp b/libraries/microDS3231/src/microDS3231.cpp
new file mode 100644
index 0000000..cff389f
--- /dev/null
+++ b/libraries/microDS3231/src/microDS3231.cpp
@@ -0,0 +1,229 @@
+#include "microDS3231.h"
+
+//static const uint8_t _ds_daysInMonth[] PROGMEM = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static uint8_t _ds_DIM(uint8_t i) {
+    return (i < 7) ? ((i == 1) ? 28 : ((i & 1) ? 30 : 31)) : ((i & 1) ? 31 : 30);
+}
+
+static uint16_t getWeekDay(uint16_t y, uint8_t m, uint8_t d) {
+    if (y >= 2000)
+    y -= 2000;
+    uint16_t days = d;
+    for (uint8_t i = 1; i < m; ++i)
+    //days += pgm_read_byte(_ds_daysInMonth + i - 1);
+    days += _ds_DIM(i - 1);
+    if (m > 2 && y % 4 == 0)
+    ++days;
+    return (days + 365 * y + (y + 3) / 4 + 4) % 7 + 1;
+}
+
+// поiхали
+MicroDS3231::MicroDS3231(uint8_t addr) : _addr(addr) {
+    Wire.begin();
+}
+
+bool MicroDS3231::begin(void){
+	Wire.begin();                       // Инит шины
+	Wire.beginTransmission(_addr);      // Зовем DS3231 по адресу
+    return (!Wire.endTransmission());   // если никто не откликнулся - возвращаем false
+}
+
+void MicroDS3231::setTime(int8_t seconds, int8_t minutes, int8_t hours, int8_t date, int8_t month, int16_t year) {
+    // защиты от дурака
+    month = constrain(month, 1, 12);
+    //date = constrain(date, 0, pgm_read_byte(_ds_daysInMonth + month - 1));
+    date = constrain(date, 0, _ds_DIM(month - 1));
+    seconds = constrain(seconds, 0, 59);
+    minutes = constrain(minutes, 0, 59);
+    hours = constrain(hours, 0, 23);
+    
+    // отправляем
+    uint8_t day = getWeekDay(year, month, date);
+    year -= 2000;
+    Wire.beginTransmission(_addr);
+    Wire.write(0x00);
+    Wire.write(encodeRegister(seconds));
+    Wire.write(encodeRegister(minutes));
+    if (hours > 19) Wire.write((0x2 << 4) | (hours % 20));
+    else if (hours > 9) Wire.write((0x1 << 4) | (hours % 10));
+    else Wire.write(hours);	
+    Wire.write(day);
+    Wire.write(encodeRegister(date));
+    Wire.write(encodeRegister(month));
+    Wire.write(encodeRegister(year));
+    Wire.endTransmission();
+}
+
+void MicroDS3231::setHMSDMY(int8_t hours, int8_t minutes, int8_t seconds, int8_t date, int8_t month, int16_t year) {
+    setTime(seconds, minutes, hours, date, month, year);
+}
+
+void MicroDS3231::setTime(DateTime time) {
+    setTime(time.second, time.minute, time.hour, time.date, time.month, time.year);
+}
+
+static int charToDec(const char* p) {
+    return (10 * (*p - '0') + (*++p - '0'));
+}
+
+void MicroDS3231::setTime(const __FlashStringHelper* stamp) {
+    char buff[25];   
+    memcpy_P(buff, stamp, 25);
+    
+    // Wed Jul 14 22:00:24 2021
+    //     4   8  11 14 17   22
+    // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
+    int h, m, s, d, mo, y;
+    h = charToDec(buff + 11);
+    m = charToDec(buff + 14);
+    s = charToDec(buff + 17);
+    d = charToDec(buff + 8);  
+    switch (buff[4]) {
+    case 'J': mo = (buff[5] == 'a') ? 1 : (mo = (buff[6] == 'n') ? 6 : 7); break;
+    case 'F': mo = 2; break;
+    case 'A': mo = (buff[6] == 'r') ? 4 : 8; break;
+    case 'M': mo = (buff[6] == 'r') ? 3 : 5; break;
+    case 'S': mo = 9; break;
+    case 'O': mo = 10; break;
+    case 'N': mo = 11; break;
+    case 'D': mo = 12; break;
+    }
+    y = 2000 + charToDec(buff + 22);
+    setTime(s, m, h, d, mo, y);
+}
+
+DateTime MicroDS3231::getTime() {
+    DateTime now;
+    Wire.beginTransmission(_addr);
+    Wire.write(0x0);
+    if (Wire.endTransmission() != 0) return now;
+    Wire.requestFrom(_addr, (uint8_t)7);
+    now.second = unpackRegister(Wire.read());
+    now.minute = unpackRegister(Wire.read());
+    now.hour = unpackHours(Wire.read());
+    now.day = Wire.read();
+    now.date = unpackRegister(Wire.read());
+    now.month = unpackRegister(Wire.read());
+    now.year = unpackRegister(Wire.read()) + 2000;
+    return now;
+}
+String MicroDS3231::getTimeString() {
+    DateTime now = getTime();
+    String str = "";
+    if (now.hour < 10) str += '0';
+    str += now.hour;
+    str += ':';
+    if (now.minute < 10) str += '0';
+    str += now.minute;
+    str += ':';
+    if (now.second < 10) str += '0';
+    str += now.second;
+    return str;
+}
+String MicroDS3231::getDateString() {
+    DateTime now = getTime();
+    String str = "";
+    if (now.date < 10) str += '0';
+    str += now.date;
+    str += '.';
+    if (now.month < 10) str += '0';
+    str += now.month;
+    str += '.';
+    str += now.year;    
+    return str;
+}
+void MicroDS3231::getTimeChar(char* array) {
+    DateTime now = getTime();
+    array[0] = now.hour / 10 + '0';
+    array[1] = now.hour % 10 + '0';
+    array[2] = ':';
+    array[3] = now.minute / 10 + '0';
+    array[4] = now.minute % 10 + '0';
+    array[5] = ':';
+    array[6] = now.second / 10 + '0';
+    array[7] = now.second % 10 + '0';
+    array[8] = '\0';
+}
+void MicroDS3231::getDateChar(char* array) {
+    DateTime now = getTime();        
+    array[0] = now.date / 10 + '0';
+    array[1] = now.date % 10 + '0';
+    array[2] = '.';
+    array[3] = now.month / 10 + '0';
+    array[4] = now.month % 10 + '0';
+    array[5] = '.';
+    itoa(now.year, array + 6, DEC);
+    array[10] = '\0';
+}
+bool MicroDS3231::lostPower(void) { // возвращает true, если 1 января 2000
+    if (getYear() == 2000 && getMonth() == 1 && getDate() == 1) return true;
+    else return false;
+}
+
+uint8_t MicroDS3231::getSeconds(void) {
+    return (unpackRegister(readRegister(0x00)));
+}
+
+uint8_t MicroDS3231::getMinutes(void) {
+    return (unpackRegister(readRegister(0x01)));
+}
+
+uint8_t MicroDS3231::getHours(void) {
+    return (unpackHours(readRegister(0x02)));
+}
+
+uint8_t MicroDS3231::getDay(void) {
+    return readRegister(0x03);
+}
+
+uint8_t MicroDS3231::getDate(void) {
+    return (unpackRegister(readRegister(0x04)));
+}
+
+uint8_t MicroDS3231::getMonth(void) {
+    return (unpackRegister(readRegister(0x05)));
+}
+
+uint16_t MicroDS3231::getYear(void) {
+    return (unpackRegister(readRegister(0x06)) + 2000);
+}
+
+// сервис
+uint8_t MicroDS3231::readRegister(uint8_t addr) {
+    Wire.beginTransmission(_addr);
+    Wire.write(addr);
+    if (Wire.endTransmission() != 0) return 0;
+    Wire.requestFrom(_addr, (uint8_t)1);
+    uint8_t data = Wire.read();
+    return data;
+}
+
+uint8_t MicroDS3231::unpackRegister(uint8_t data) {
+    return ((data >> 4) * 10 + (data & 0xF));
+}
+
+uint8_t MicroDS3231::encodeRegister(int8_t data) {
+    return (((data / 10) << 4) | (data % 10));
+}
+
+uint8_t MicroDS3231::unpackHours(uint8_t data) {
+    if (data & 0x20) return ((data & 0xF) + 20);
+    else if (data & 0x10) return ((data & 0xF) + 10);
+    else return (data & 0xF);
+}
+
+float MicroDS3231::getTemperatureFloat(void) {
+    return (getTemperatureRaw() * 0.25f);
+}
+
+int MicroDS3231::getTemperature(void) {
+    return (getTemperatureRaw() >> 2);
+}
+
+int MicroDS3231::getTemperatureRaw(void) {
+    Wire.beginTransmission(_addr);
+    Wire.write(0x11);
+    Wire.endTransmission();
+    Wire.requestFrom(_addr, (uint8_t)2);
+    return ((int8_t)Wire.read() << 2) + (Wire.read() >> 6);
+}
\ No newline at end of file
diff --git a/libraries/microDS3231/src/microDS3231.h b/libraries/microDS3231/src/microDS3231.h
new file mode 100644
index 0000000..b93f79c
--- /dev/null
+++ b/libraries/microDS3231/src/microDS3231.h
@@ -0,0 +1,82 @@
+/*
+    Лёгкая библиотека для работы с RTC DS3231 для Arduino
+    Документация: 
+    GitHub: https://github.com/GyverLibs/microDS3231
+    Возможности:
+    - Чтение и запись времени
+    - Вывод в char* и String
+    - Чтение температуры датчика
+    
+    Egor 'Nich1con' Zakharov & AlexGyver, alex@alexgyver.ru
+    https://alexgyver.ru/
+    MIT License
+
+    Версии:
+    v1.2 - добавлены ограничения на вводимые в setTime числа. Также нельзя ввести 29 февраля увы =)
+    v1.3 - пофикшено зависание, когда модуль отключен но опрашивается
+    v1.4 - незначительный фикс
+    v2.0 - новые возможности, оптимизация и облегчение
+    v2.1 - добавил вывод температуры, вывод в String и char
+    v2.2 - исправлены дни недели (пн-вс 1-7)
+    v2.3 - небольшие исправления, оптимизация, изменён порядок вывода даты
+    v2.4 - исправлена установка времени компиляции
+	v2.5 - добавлен begin для проверки наличия модуля на линии
+    v2.6 - исправлены отрицательные температуры
+*/
+
+#ifndef microDS3231_h
+#define microDS3231_h
+//#include <microWire.h>	// выбор между библиотеками Wire и microWire
+#include <Wire.h>
+#include "buildTime.h"
+
+#include <Arduino.h>
+#define COMPILE_TIME F(__TIMESTAMP__)
+
+struct DateTime {
+    uint8_t second; 
+    uint8_t minute;
+    uint8_t hour;
+    uint8_t day;
+    uint8_t date;
+    uint8_t month;
+    uint16_t year;
+};
+
+class MicroDS3231 {
+public:
+    MicroDS3231(uint8_t addr = 0x68);               // конструктор. Можно передать адрес    
+	bool begin(void);								// инициализация, вернет true, если RTC найден
+    void setTime(const __FlashStringHelper* stamp);	// установка времени == времени компиляции
+    void setTime(DateTime time);	                // установить из структуры DateTime
+    void setTime(int8_t seconds, int8_t minutes, int8_t hours, int8_t date, int8_t month, int16_t year);	// установка времени
+    void setHMSDMY(int8_t hours, int8_t minutes, int8_t seconds, int8_t date, int8_t month, int16_t year);	// установка времени тип 2
+    
+    DateTime getTime(void);			// получить в структуру DateTime
+    uint8_t getSeconds(void);		// получить секунды
+    uint8_t getMinutes(void);		// получить минуты
+    uint8_t getHours(void);			// получить часы
+    uint8_t getDay(void);			// получить день недели
+    uint8_t getDate(void);			// получить число
+    uint16_t getYear(void);			// получить год
+    uint8_t getMonth(void);			// получить месяц
+    
+    String getTimeString();			// получить время как строку вида HH:MM:SS
+    String getDateString();			// получить дату как строку вида DD.MM.YYYY
+    void getTimeChar(char* array);	// получить время как char array [8] вида HH:MM:SS
+    void getDateChar(char* array);	// получить дату как char array [10] вида DD.MM.YYYY       
+    
+    bool lostPower(void);			// проверка на сброс питания
+    float getTemperatureFloat(void);// получить температуру float
+    int getTemperature(void);		// получить температуру int
+    
+private:
+    uint8_t encodeRegister(int8_t data);
+    int getTemperatureRaw(void);
+    uint8_t readRegister(uint8_t addr);
+    uint8_t unpackRegister(uint8_t data);
+    uint8_t unpackHours(uint8_t data);
+    const uint8_t _addr;
+};
+
+#endif
\ No newline at end of file
-- 
GitLab