/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
//////////////////                                               ////////////////////
//////////////////    О П И С А Н И Е   П Е Р Е М Е Н Н Ы Х      ////////////////////
//////////////////                                               ////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////


// Переменные

// Строки (объект), длина переменная.
String        VERPOS = "OMSDS161114-OPN", /* Версия прошивки scale и серийный номер. */// 022
// Версия под Бурсакова вес в 6, 14, 20.30, отчет в 21.
                       ringNumber, /* Номер звонящего и прочие моменты */
                       numMaster, /* Мастер телефон. */
                       numBoss = "+79150403638", /* босс телефон. */
                       currStr = "", /* Стро28ка полученная от GSM модуля. */
                       ring = "", /* Переменная для выделения звонка. Возможно лишняя. */
                       SMS = "", /* Переменная для СМС, скорее всего лишняя, проверить. */
                       SMSpass = "999", /* СМС пароль на запрос веса по умолчанию. */
                       GSMLevel = "0", // Уровень сигнала сотовой сети.
                       pass; // Для разных операций вырезания текста.

// Цифровые данные с плавающей точкой от -3.4028235E+38 до 3.4028235E+38 занимает 4 байта.
float         Weight, /* Вес в системе */
              uTek,
              setScale = 19600, /* Коэффициент калибровки по весу. 19756 */
              predWeight, /* Вес предыдущей итерации. */
              oldWeight, /* Что то предыдущее, посмотреть. */
              uSr, /* Усредненное бортовое напряжение. */
              uPred, /* Предыдущее значение напряжения в итерации. */
              tempFloat,
              temperature; /* Температура в системе в градусах. */

// Длинное знаковое число от -2,147,483,648 до 2,147,483,647, занимает 4 байта.
long          acpNol; /* Вес тары с АЦП. */

// Длинное знаковое число от 0 до 4,294,967,295, занимает 4 байта.
unsigned long etalonWeight, /* Вес эталона от АЦП */
         setArduino; /* Длительность работы системы. */

// Целое число от -32,768 до 32,767, занимает 2 байта.
int           enterWeight, /* Введенный вес */
              count = 0,   /* Счетчик работы с буфером RS порта */
              kolUsr = 2, /* Глубина усреднения данных по весу. */
              intTemp; // Временная переменная для любой int хрени.

// Целое число от 0 до 64,535, занимает 2 байта.
unsigned int  start, /* Начало какого то процесса по времени. */ stopp, /* Окончание какого то процесса по времени. */ delt, /* Разница временных измерений. */
         starts, /* Количество стартов системы.*/
         year = 2014; /* Год. */

// Целое число от -32,768 до 32,767, занимает 2 байта.
volatile int  sleep_count = 0; /* Keep track of how many sleep проверить.  */

// Целое число от -32,768 до 32,767, занимает 2 байта.
const int     interval = 12, /* Длительность сна в минутах. 13 */
              sleep_total = (interval * 60) / 8; /* Приблизительное кол-во циклов для обеспечения длительности сна. */

// Символьная переменная по 1 байту.
char          buffer2[64]; /* Буфер для приема с RS порта. */

// Цифровая переменная 1 байт.
byte          keyPin = 2, /* Номер порта кнопки. */
              etalonWeight1, /* Первый байт веса эталона */ etalonWeight2, /* Второй байт веса эталона */ etalonWeight3, /* Третий байт веса эталона */
              enterWeight1, /* Первый байт введенного веса */ enterWeight2, /* Второй байт введенного веса */ enterWeight3, /* Третий байт введенного веса */
              kolUsrU = 5, /* Глубина усреднения данных по напряжению. */
              second = 00, /* Секунды. */ minute = 59, /* Минуты. */ hour = 11, /* Часы. */ dayOfMonth = 17, /* День. */ month = 01, /* Месяц. */
              sminute = 0, /* Проверить это. */
              errors = 0, // Количество ошибок отсутствия связи с GSM.
              celWeight,
              drobWeight,
              b100[8] = { B10101, // Символ антенны.
                          B10101,
                          B01110,
                          B00100,
                          B00100,
                          B00100,
                          B00100,
                          B00000,
                        },
                        workYear,
                        workMonth,
                        tempByte,
                        addrTerm[8];

// Цифровая переменная 1 бит.
boolean       keyType = 0, /* Тип активного нажатия кнопки. 0 - нормальнозамкнута. 1 - нормальноразомкнута. */
              goodNight = 0, /* Разрешение спать. */
              perm23 = 0, /* Разрешение слать СМС в 23 часа. */
              interNet = 0, // Показатель регистрации в GSM сети.
              vesPZU = 1, // Разрешение сохранения веса в ПЗУ.
              bTemp,
              oldAlarm,
              ALARM = 0, // Разрешение сигналить ALARM.
              BLOCK = 0; // Блокировка весов.

// Карта EEPROM памяти.
// адрес 0 - вес тары. младший.
// адрес 1 - вес тары. средний.
// адрес 2 - вес тары. старший байт.
// адрес 3 - вес эталона младший.
// адрес 4 - вес эталона средний.
// адрес 5 - вес эталона старший.
// адрес 6 - введенный вес эталона.
// адрес 7 - Старты младшая часть.
// адрес 8 - Старты старшая часть.
// адрес 9 - использование GSM.
// Boss телефон:
// адрес 10 - +
// адрес 11 - 7
// адрес 12 - 9
// адрес 13 - 1
// адрес 14 - 5
// адрес 15 - 0
// адрес 16 - 4
// адрес 17 - 0
// адрес 18 - 3
// адрес 19 - 6
// адрес 20 - 3
// адрес 21 - 8
// адрес 22 - запас1
// адрес 23 - запас2
// master телефон:
// адрес 24 - +
// адрес 25 - 3
// адрес 26 - 7
// адрес 27 - 5
// адрес 28 - 2
// адрес 29 - 9
// адрес 30 - 6
// адрес 31 - 4
// адрес 32 - 7
// адрес 33 - 3
// адрес 34 - 2
// адрес 35 - 2
// адрес 36 - запас1
// адрес 37 - запас2
//
// адрес 40 - 1 dig1  пароль на запрос веса.
// адрес 41 - 2 dig2
// адрес 42 - 3 dig3
//
// адрес 50 - goodNight - режим сна
// адрес 51 - perm23 - разрешение на отправку СМС в 23 часа
// адрес 52 - Старый вес знак (0-минус, 1 и более -плюс).
// адрес 53 - Старый вес целая часть.
// адрес 54 - Разрешение режима ALARM.
//
//адрес 55 - калибровка младший
//адрес 56 - калибровка средний
//адрес 57 - калибровка старший
//          в 5 утра
//адрес 58 - вес целые
//адрес 59 - вес дробные
//адрес 60 - резерв
//          в 14 часов
//адрес 61 - вес целые
//адрес 62 - вес дробные
//адрес 63 - резерв
//          в 23 часа
//адрес 64 - вес целые
//адрес 65 - вес дробные
//адрес 66 - резерв
//          Дата смерти.
//адрес 67 - год смерти.
//адрес 68 - месяц смерти.
//
//адрес 69 - старое положение контура защиты.

#include <EEPROM.h>
#include <SoftwareSerial.h>
#include "HX711.h"
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "RTClib.h"
#include <OneWire.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

// Создание объектов.
SoftwareSerial GSMm(8, 12);
HX711 scale(A2, A1);
LiquidCrystal_I2C lcd(0x27, 16, 2);
RTC_DS1307 RTC;
OneWire  ds(3);

/*=======================================================================
=========================================================================
===========================                 =============================
===========================    S E T U P    =============================
===========================                 =============================
=========================================================================
=======================================================================*/

void setup() {
  setUpSystem();
}

/*====================================================================================
======================================================================================
==============================               =========================================
==============================    L O O P    =========================================
==============================               =========================================
======================================================================================
====================================================================================*/

void loop()
{
  autoRestart(); // Check
  getTime(); // Check
  getPower(); // Check
  getWeight(); // Check
  getTemperature(); // Check
  Serial.println(Weight);
  writeMainLCD(); // Check
  MENU();

  checkGSM();
  if (interNet == 1) {
    GSMRead(); // Check
    SMSSetTime(); // Check
    changeNumBoss(); // Check
    changeNumMaster();
    changeSMSPassword(); // Check
    send00SMSOnPassword();
    sendBaseSMSOnSMSRequest();
    sendBaseSMSOnPhoneCall();
    send00SMS();
    sendAlarmSMS();
    receiveDyeDate();
  }

  writeEEPROM_5_14_23();
  goToSleepMode();
  blockSystem();
  LCDOff();

  if (millis() / 1000 % 10 == 0 & bTemp == 1) {
    Serial.println(millis() / 1000);
    bTemp = 0;
  }
  if (millis() / 1000 % 10 != 0 & bTemp == 0) {
    bTemp = 1;
  }

  //Serial.println("setTime");
  // Установка времени
  // RTC.adjust(DateTime(year, month, dayOfMonth, hour, minute, 1));
  //RTC.adjust(DateTime(year, month, dayOfMonth, 14, 00, 1));
  //RTC.adjust(DateTime(2015, 11, 06, 12, 37, 1));

  delay(500);
  
}


/*=============================================================================
===============================================================================
===================                     =======================================
===================    Ф У Н К Ц И И    =======================================
===================                     =======================================
===============================================================================
=============================================================================*/

void MENU() {
  
  // Переборка меню от нажатия кнопки
  
  if (BLOCK==0) {
  start = 0;
  int cases = 99; // для одноразовой прорисовки текста в кейсе
  if (digitalRead(keyPin) == keyType && start == 0) {
    newSet(); wdt_reset();
    lcd.init(); lcd.backlight(); lcd.createChar(0, b100); // Переинициализация LCD.
    start = millis();
    stopp = millis();
    while (digitalRead(keyPin) == LOW) {
      wdt_reset();
      delt = (stopp - start) / 2000;

      if (cases == 99) {
        lcd.clear();  //lcd.print("     Me\xbd\xc6"); // МЕНЮ
        lcd.setCursor(5, 0);
        lcd.print("Menu");
      }
      switch (delt) { // Вывод меню
        case 0:
          if (cases != 0) {
            cases = 0;
          }
          break;
        case 1: // версия
          if (cases != 1) {
            lcd.setCursor(0, 1); lcd.print("Version"); //lcd.print("Bepc\xb8\xc7"); // версия
            cases = 1;
          }
          break;
        case 2: // обнуление
          if (cases != 2) {
            lcd.setCursor(0, 1); lcd.print("Set to zero"); //lcd.print("O\xb2\xbd""y\xbb""e""\xbd\xb8""e"); // обнуление
            cases = 2;
          }
          break;
        case 3: // калибровка
          if (cases != 3) {
            lcd.setCursor(0, 1); lcd.print("Calibration"); //lcd.print("Ka\xbb\xb8\xb2""po""\xb3""ka"); // калибровка
            cases = 3;
          }
          break;
        case 4: // сон
          if (cases != 4) {
            lcd.setCursor(0, 1); lcd.print("Sleep      "); //lcd.print("Co""\xbd""?"); // сон?
            cases = 4;
          }
          break;
        case 5: // ALARM
          if (cases != 5) {
            lcd.setCursor(0, 1); lcd.print("Alarm"); // ALARM?
            cases = 5;
          }
          break;
        case 6: // ВЫХОД
          if (cases != 6) {
            lcd.setCursor(0, 1); lcd.print("Exit "); // ВЫХОД
            cases = 6;
          }
          break;
        case 7: // сброс таймеров
          if (cases != 7) {
            start = millis();
            cases = 7;
          }
          break;
      }
      stopp = millis();
    }
    // выполнение вариантов нажатой клавиши
    switch (delt)
    {
      case 0:
        break;
      case 1: // версия
        ver();
        newSet();
        break;
      case 2: // обнуление
        setToZero();
        newSet();
        break;
      case 3: // калибровка
        calibrating();
        newSet();
        break;
      case 4: // сон
        setSleepMode();
        newSet();
        break;
      case 5: // ALARM
        setAlarmMode();
        newSet();
        break;
      case 6: // ВЫХОД
        newSet();
        break;
    }
  }

}}

void writeMainLCD() {
  // блок 18 вывод на LCD
  // Вес.
  lcd.setCursor(0, 0); lcd.print("Bec  ");
  if (Weight <= 0 and Weight >= -0.09) Weight = -Weight;
  { // блок изменения позиции вводимого веса.
    if (Weight >= -99.99 and Weight <= -10) lcd.setCursor(3, 0);
    if (Weight >= -9.99 and Weight < 0) lcd.setCursor(4, 0);
    if (Weight >= 0 and Weight <= 9.99) lcd.setCursor(5, 0);
    if (Weight >= 10 and Weight <= 99.99) lcd.setCursor(4, 0);
    if (Weight >= 100 and Weight <= 200 or Weight == 199) lcd.setCursor(3, 0);
  }
  lcd.print(" "); lcd.print(Weight);
  lcd.setCursor(9, 0); lcd.print(" ");

  // Напряжение.
  lcd.setCursor(10, 0); lcd.print(" ");
  if (uSr < 10) lcd.print(" ");
  lcd.print(uSr); lcd.setCursor(15, 0); lcd.print("v");

  // Переключение по 20 сек.
  if ((millis() / 10000) % 2 == 0 ) {
    // Вывод температуры.
    if (temperature==1234567890){lcd.setCursor(0, 1); lcd.print("          ");}
    else{
    lcd.setCursor(0, 1); lcd.print("  "); lcd.setCursor(2, 1); if (temperature < 0) {} else {
      lcd.print("+");
    } lcd.print(temperature); lcd.setCursor(7, 1); lcd.print("C   "); 
    }
    // Выводим антенну.
    lcd.setCursor(9, 1); lcd.print(GSMLevel); lcd.print("  ");
    lcd.setCursor(11, 1); if (interNet == 1) {lcd.write((byte)0); lcd.print(" ");} else lcd.print("  ");
    if (digitalRead(4)==HIGH){
          lcd.setCursor(13, 1);
      lcd.print("o");
    }
    else{
           lcd.setCursor(13, 1);
      lcd.print("C");
    }
    if (goodNight == 0) {
      lcd.setCursor(14, 1);
      lcd.print("s");
    } else {
      lcd.setCursor(14, 1);
      lcd.print("S");
    }
    if (ALARM == 0) {
      lcd.setCursor(15, 1);
      lcd.print("a");
    } else {
      lcd.setCursor(15, 1);
      lcd.print("A");
    }
  }
  else {
    // вывод времени
    lcd.setCursor(0, 1); if (hour < 10)lcd.print("0"); lcd.print(hour); lcd.print(":"); if (minute < 10)lcd.print("0"); lcd.print(minute); lcd.print(" ");
    if (dayOfMonth < 10)lcd.print("0"); lcd.print(dayOfMonth); lcd.print("\/"); if (month < 10)lcd.print("0"); lcd.print(month); lcd.print("\/"); if (year < 10)lcd.print("0"); lcd.print(year);
  }

}

void getTemperature() {
  ds.reset();
  ds.select(addrTerm);
  ds.write(0x44);
  delay(100);
  ds.reset();
  ds.select(addrTerm);
  ds.write(0xBE);

  byte data[9];
  for ( int i = 0; i < 9; i++) {
    data[i] = ds.read();
  }



  int16_t raw = (((int16_t)data[1]) << 8) | data[0];
  temperature = ((float)(raw >> 1) - 0.25 + ((float)(data[7] - data[6]) / (float)data[7] )) / 79 * 10;
  
    if (OneWire::crc8(data, 8) != data[8]) {
    temperature = 1234567890;
  }
}

void getWeight() {
  // Блок работы с ВЕСАМИ.
  tempFloat = (scale.read() - acpNol) / setScale;
  //if (tempFloat>(Weight+50)){}
  //else 
  {
  if (predWeight == 0) predWeight = tempFloat;
  Weight = (predWeight * (kolUsr - 1) + tempFloat) / kolUsr;
  predWeight = Weight;
  }
}

void getPower() {
  uTek = myPower(); // блок 15 получить напряжение системы
  if (uPred == 0) uPred = uTek;
  uSr = (uPred * (kolUsrU - 1) + uTek) / kolUsrU;
  uPred = uSr;
}

float myPower() { // Программа отображения напряжения питания с сотыми долями.
  uTek = analogRead(A0);
  uTek = uTek / 40;
  return uTek;
}


void getTime() {
  // Определяем время.
  DateTime now = RTC.now(); year = now.year(); month = now.month(); dayOfMonth = now.day(); hour = now.hour(); minute = now.minute(); second = now.second();
}

void goToSleepMode() {
  // Засыпание.
  if (goodNight & (millis() / 1000 - setArduino) > 182) {
    sleep_count = 0; digitalWrite(13, LOW); pinMode(13, INPUT);
    MCUSR = 0;
    watchdogOn();
    goToSleep();
    while (sleep_count < sleep_total) {
      goToSleep();
    }
    MCUSR = 1;
    wdt_enable (WDTO_8S);
    newSet();
    modulUp();
  }
}

void autoRestart() {
  // Профилактический перезапуск системы.
  if (millis() / 1000 > 912) {
    digitalWrite(13, LOW);
    delay(10000);
    asm volatile ("  jmp 0");
  }
}

void blockSystem() {
  // Блокирование работы системы.
  wdt_reset();
  BLOCK = 0;
  // Блокировка по температуре.
  /*
  if ((temperature == 1234567890)) {
    if (workYear == 88 and workMonth == 88){BLOCK=0;}
    else
    {
      BLOCK = 1;
      lcd.clear();
      lcd.setCursor(4, 0); lcd.print("blocked");
      lcd.setCursor(0, 1); lcd.print("Sergey@BeloFF.ru");
      delay(7000);
    }
    wdt_reset();
  }
  */
  // Блокировка по времени.
  if ((year > (workYear + 2000)) or (year == (workYear + 2000) and month >= workMonth)) {
    BLOCK = 1;
    lcd.clear();
    lcd.setCursor(4, 0); lcd.print("BLOCKED");
    lcd.setCursor(0, 1); lcd.print("Sergey@BeloFF.ru");
    delay(7000);
    wdt_reset();
  }
}

void receiveDyeDate() {
  // Прием даты смерти. Индекс DH1299 - 12 месяц 99 год.
  intTemp = currStr.indexOf("DH");
  //Serial.println(currStr);
  if (intTemp != -1) {
    ringNumber = currStr.substring(intTemp + 2, intTemp + 6);

    //Serial.println(currStr);
    //Serial.println(ringNumber[0]);
    //Serial.println(ringNumber[1]);
    //Serial.println(ringNumber[2]);
    //Serial.println(ringNumber[3]);
    //Serial.println(byte(ringNumber[0]));
    //Serial.println(byte(ringNumber[1]));
    //Serial.println(byte(ringNumber[2]));
    //Serial.println("---");
    workMonth = ((int(ringNumber[0]) - 48) * 10) + (int(ringNumber[1] - 48));
    workYear = ((int(ringNumber[2]) - 48) * 10) + (int(ringNumber[3]) - 48);

    EEPROM.write(67, workYear);
    EEPROM.write(68, workMonth);
    sendSMS00(numBoss, 1);
    //Serial.println(workMonth);
    //Serial.println(workYear);
  }
}

void sendAlarmSMS() {
  // ALARM режим. Экстренная отправка СМС при падении веса и изменении контура.

  // Если изменился периметр.
  if (interNet == 1 and ALARM == 1 and digitalRead(4) != oldAlarm) {
    oldAlarm = !oldAlarm; EEPROM.write(69, oldAlarm); alarmSMS(numMaster);
    //Serial.println(oldAlarm);
  }

  // Если упало питание
  if ((millis() / 1000) % 310 == 0 and interNet == 1 and ALARM == 1) {
    if (uSr < 7 and interNet == 1 and ALARM == 1) {
      alarmSMS(numMaster);
    }
  }

  // Если упал вес за 1 мин более чем на 1 кг.
  if ((millis() / 1000) % 60 == 0 and interNet == 1 and ALARM == 1) {

    if (EEPROM.read(52) > 250 or EEPROM.read(53) > 250) {
      if (Weight < 0) EEPROM.write(52, 0);  // Если в EEPROM было пусто - записать вес.
      else EEPROM.write(52, 1);
      tempByte = Weight;
      EEPROM.write(53, tempByte);
    }

    intTemp = EEPROM.read(52) * EEPROM.read(53);

    if ((intTemp - Weight) > 1) {
      alarmSMS(numMaster);
    }

    if (Weight > 0) {
      EEPROM.write(52, 1);
      tempByte = Weight;
      EEPROM.write(53, tempByte);
    }
    else {
      EEPROM.write(52, 0);
      tempByte = (Weight * -1);
      EEPROM.write(53, tempByte);
    }
  }
  wdt_reset();
}

void LCDOff() {
  if ((millis() / 1000) % 300 == 0 ) {
    lcd.noBacklight();
  }
}


void checkGSM() {
  // Проверка сотовой сети.
  if (millis() / 1000 % 6 == 0)    {   // Проверка соединения с сотовой сетью
    GSMm.print("AT+COPS?\r"); delay(200); GSMRead();
    if (currStr.indexOf("+COPS: 0,") != -1)interNet = 1; else interNet = 0;
    if (currStr.indexOf("OK") != -1) {} else errors++; // если нет связи с GSM увеличить счетчик ошибок
    if (errors > 10) {
      digitalWrite(13, LOW);
      delay(10000);
      asm volatile ("  jmp 0");
    }
    GSMm.print("AT+CSQ\r"); delay(200); GSMRead();
    //GSMLevel = currStr.substring(currStr.indexOf("+CSQ:") + 6, currStr.indexOf("+CSQ:") + 8);
    GSMLevel = currStr.substring(currStr.indexOf("+CSQ:") + 6, currStr.indexOf(",0"));

  }
}

void send00SMSOnPassword() {
  // Отправка СМС отчет по паролю 00.
  if (currStr.indexOf("00" + SMSpass) != -1) {
    numMaster = currStr.substring(currStr.indexOf("\"+") + 1, currStr.indexOf("\","));
    sendSMS00(numMaster, 0); // отправили СМС о смене numMaster
    newSet();
  }
}

void send00SMS() {
  // отправка СМС в 00:00
  if (interNet == 1) {
    if (hour == 21 & perm23 > 0) {
      sendSMS00(numMaster, 1);
      perm23 = 0;
      EEPROM.write(51, perm23);
    }
    if (hour != 21 & perm23 == 0) {
      perm23 = 1;
      EEPROM.write(51, perm23);
    }
  }
}

void writeEEPROM_5_14_23() {
  // Запись веса в ПЗУ в 5 в 14 и в 23 часа.
  byte celOld, drobOld;
  if (hour == 5 & vesPZU == 1) {
    if (Weight < 0) {
      Weight = -Weight;
      drobOld = 100;
    } else {
      drobOld = 0;
    }
    celOld = Weight; drobOld = drobOld + ((Weight - celOld) * 100); EEPROM.write(58, celOld); EEPROM.write(59, drobOld); vesPZU = 0;
  }
  if (hour == 14 & vesPZU == 1) {
    if (Weight < 0) {
      Weight = -Weight;
      drobOld = 100;
    } else {
      drobOld = 0;
    }
    celOld = Weight; drobOld = drobOld + ((Weight - celOld) * 100); EEPROM.write(61, celOld); EEPROM.write(62, drobOld); vesPZU = 0;
  }
  if (hour == 20 & (minute>29 & minute<59) & vesPZU == 1) {
    if (Weight < 0) {
      Weight = -Weight;
      drobOld = 100;
    } else {
      drobOld = 0;
    }
    celOld = Weight; drobOld = drobOld + ((Weight - celOld) * 100); EEPROM.write(64, celOld); EEPROM.write(65, drobOld); vesPZU = 0;
  }
  if (vesPZU == 0 & (hour == 6 or hour == 7 or hour == 8 or hour == 9 or hour == 10 or hour == 11 or hour == 12 or hour == 13 or hour == 15 or hour == 16 or hour == 17 or hour == 18 or hour == 19 or hour == 21 or hour == 22 or hour == 23 or hour == 0 or hour == 1 or hour == 2 or hour == 3 or hour == 4)) vesPZU = 1;
}

void sendBaseSMSOnPhoneCall() {
  //SMSSetTime()
  // Отправка СМС по звонку.
  if (currStr.indexOf("RING") != -1) { // если это звонок..
    GSMm.write("AT+CLCC\r"); delay(500); GSMRead();
    delay(2000);
    GSMm.write("ATH\r");

    ringNumber = currStr.substring(currStr.indexOf("\"+") + 1, currStr.indexOf("\","));

    if ((ringNumber.indexOf(numBoss) != -1) or (ringNumber.indexOf(numMaster) != -1)) {
      //Serial.println("vislat");

      sendBaseSMS(ringNumber, 1);
      currStr = ""; ringNumber = "";
    }
    newSet();
  }
}

void sendBaseSMSOnSMSRequest() {
  //SetTime();
  // Отправка веса по факту прихода СМС с паролем.
  intTemp = currStr.indexOf(SMSpass);
  if (intTemp != -1) {
    ringNumber = currStr.substring(currStr.indexOf("\"+") + 1, currStr.indexOf("\","));
    sendBaseSMS(ringNumber, 0);  // отправили СМС
    currStr = ""; ringNumber = "";
    newSet();
  }
}

void changeSMSPassword() {
  //SetTime();
  // Смена пароля запроса веса
  intTemp = currStr.indexOf("pw");
  if (intTemp != -1) {
    ringNumber = currStr.substring(currStr.indexOf("\"+") + 1, currStr.indexOf("\","));
    if ((ringNumber.indexOf(numBoss) != -1) or (ringNumber.indexOf(numMaster) != -1)) {
      ringNumber = currStr.substring(intTemp + 2, intTemp + 5);
      EEPROM.write(40, ringNumber[0]); EEPROM.write(41, ringNumber[1]); EEPROM.write(42, ringNumber[2]);
      SMSpass = ringNumber;
      ringNumber = currStr.substring(currStr.indexOf("\"+") + 1, currStr.indexOf("\","));
      sendBaseSMS(ringNumber, 1);
      //Serial.println("password");
    }
    newSet();
  }
}

void changeNumMaster() {
  //SetTime();
  // Смена numMaster
  for (tempByte = 0; tempByte < 13; tempByte++) {
    ringNumber[tempByte] = 255;
  }
  pass = VERPOS.substring(VERPOS.indexOf("-") + 1, VERPOS.indexOf("-") + 3);
  if (currStr.indexOf("\r\n" + pass) != -1) {
    ringNumber = currStr.substring(currStr.indexOf("\"+") + 1, currStr.indexOf("\","));
    EEPROM.write(25, ringNumber[1]); EEPROM.write(26, ringNumber[2]); EEPROM.write(27, ringNumber[3]); EEPROM.write(28, ringNumber[4]); EEPROM.write(29, ringNumber[5]);
    EEPROM.write(30, ringNumber[6]); EEPROM.write(31, ringNumber[7]); EEPROM.write(32, ringNumber[8]); EEPROM.write(33, ringNumber[9]); EEPROM.write(34, ringNumber[10]);
    EEPROM.write(35, ringNumber[11]); EEPROM.write(36, ringNumber[12]); EEPROM.write(37, ringNumber[13]);
    numMaster = ringNumber;
    sendSetNumMasterSMS(numMaster); // отправили СМС о смене numMaster
    delay(5000);
    wdt_reset();
    delay(5000);
    wdt_reset();
    sendSetNumMasterSMS(numBoss); // отправили СМС о смене numMaster
    newSet();
  }
}


void changeNumBoss() {
  //SetTime();
  // Смена numBOSS
  if (currStr.indexOf("BOSS") != -1 ) {
    for (byte i = 0; i < 13; i++) {
      ringNumber[i] = 255;
    }
    ringNumber = currStr.substring(currStr.indexOf("\"+") + 2, currStr.indexOf("\","));

    EEPROM.write(11, ringNumber[0]); EEPROM.write(12, ringNumber[1]); EEPROM.write(13, ringNumber[2]); EEPROM.write(14, ringNumber[3]); EEPROM.write(15, ringNumber[4]);
    EEPROM.write(16, ringNumber[5]); EEPROM.write(17, ringNumber[6]); EEPROM.write(18, ringNumber[7]); EEPROM.write(19, ringNumber[8]); EEPROM.write(20, ringNumber[9]);
    EEPROM.write(21, ringNumber[10]); EEPROM.write(22, ringNumber[11]); EEPROM.write(23, ringNumber[12]);
    numBoss = ringNumber;
    //Serial.println(numBoss);
    sendSetNumMasterSMS(numBoss); // отправили СМС о смене numMaster
    newSet();
  }
}

void SMSSetTime() {
  // SMS установка времени
  if (currStr.indexOf("STIME") != -1) {SetTime();} 
    // Ресетнуть.
  if (currStr.indexOf("RESET") != -1) {
    sendBaseSMS(numMaster, 1);
    delay(10000);
    asm volatile ("  jmp 0"); // программный ребут.
  }
}
    
    
void SetTime()
{
    Serial.println(currStr);
    //year
    pass = currStr.substring(currStr.indexOf("/") - 2, currStr.indexOf("/"));
    int temp1 = int(pass[0]) - 48;
    int temp2 = int(pass[1]) - 48;
    if (0 < (temp1 * 10 + temp2) < 100) year = 2000 + temp1 * 10 + temp2;
    //month
    pass = currStr.substring(currStr.indexOf("/") + 1, currStr.indexOf("/") + 3);
    temp1 = int(pass[0]) - 48; // 48 смещение с таблице кодов.
    temp2 = int(pass[1]) - 48;
    if (0 < (temp1 * 10 + temp2) < 13)month = temp1 * 10 + temp2;
    //dayOfMonth
    pass = currStr.substring(currStr.indexOf("/") + 4, currStr.indexOf("/") + 6);
    temp1 = int(pass[0]) - 48;
    temp2 = int(pass[1]) - 48;
    if (0 < (temp1 * 10 + temp2) < 32)dayOfMonth = temp1 * 10 + temp2;
    //hour
    pass = currStr.substring(currStr.indexOf("/") + 7, currStr.indexOf("/") + 9);
    temp1 = int(pass[0]) - 48;
    temp2 = int(pass[1]) - 48;
    if (0 <= (temp1 * 10 + temp2) < 24)hour = temp1 * 10 + temp2;
    //minute
    pass = currStr.substring(currStr.indexOf("/") + 10, currStr.indexOf("/") + 12);
    temp1 = int(pass[0]) - 48;
    temp2 = int(pass[1]) - 48;
    if (0 <= (temp1 * 10 + temp2) < 60)minute = temp1 * 10 + temp2;
    RTC.adjust(DateTime(year, month, dayOfMonth, hour, minute, 1));
    newSet();
    //Serial.println("SetTime");
    
  }


void setUpSystem() {

  wdt_disable();
  wdt_enable (WDTO_8S); // ВАЖНО - не включать просто так. Надо менять загрузчик. Если не поменять то процессор упадет в BootLoop. 

  // Адрес датчика температуры.
  // 28 FF D5 34 69 14 4 1F - 66
  // 28 FF 4B 45 69 14 4 2D - Казань тест 065.
  // 28 FF A3 8F 64 15 1 0 - 69 Обь Дмитрий
  // 28 FF B1 D0 64 15 3 1 - 77 Обь на замену 69
  // 28 FF 7 ED 64 15 3 7 - 87
  // 28 FF BA B3 64 15 1 D5 - 106 
  // 28 FF E2 61 91 15 1 C0 - 107 Каунас
  // 28 FF FB 60 91 15 1 C0 - 108 Каунас 2
  // 28 FF E2 B5 64 15 1 77 - 109 Каунас 3
  // 28 FF 12 3C 91 15 1 23 - 110 Каунас 4
  // 28 FF 42 A4 64 15 1 F3 - 111 Каунас 5
  // 28 FF 33 F8 64 15 2 7B - 114 Маяк
  // 28 FF 5B C9 64 15 3 CD - 117
  // 118 - 28 FF EB 8D 64 15 2 32 viost
// 119 - 28 FF DE F6 64 15 3 6
  // 120 - 28 FF 4 C6 64 15 3 AD
  // 121 - 28 FF C3 23 91 15 3 AE
  // 122 -  28 4E 37 1 0 0 80 AE
  // 123 - 28 88 61 3 0 0 80 8D
  // 124 - 28 5B 3A 1 0 0 80 F2
  // 125 - 28 B 59 3 0 0 80 84
  // 126 - 28 F0 37 1 0 0 80 BA
  
  //addrTerm[0] = 0x28;
  //addrTerm[1] = 0xF0;
  //addrTerm[2] = 0x37;
  //addrTerm[3] = 0x01;
  //addrTerm[4] = 0x00;
  //addrTerm[5] = 0x00;
  //addrTerm[6] = 0x80;
  //addrTerm[7] = 0xBA;
  
  

  // Включение системы.
  modulUp();

  // Сброс в default.
  if (digitalRead(2) == keyType) setToDefault();

  // Приветствие.
  lcd.clear();
  //lcd.setCursor(0, 0); lcd.print("\xa4\xe3""pa""\xb3""c""\xbf\xb3""y""\xb9\xbf""e,"); //Здравствуйте,
  //lcd.setCursor(0, 1); lcd.print("     ...o""\xb6\xb8\xe3""a""\xb9\xbf""e"); //...ждите
  lcd.setCursor(0, 0); lcd.print("Hello"); //Здравствуйте,
  lcd.setCursor(0, 1); lcd.print("...one second"); //...ждите
  
  ds.search(addrTerm);

  // Получение состояния режимов.
  if (EEPROM.read(50) > 1) EEPROM.write(50, goodNight); else goodNight = EEPROM.read(50); // режим сна
  if (EEPROM.read(54) > 1) EEPROM.write(54, ALARM); else ALARM = EEPROM.read(54); // режим ALARM

  // Получить numBoss.
  if (EEPROM.read(11) > 250) {}
  else {
    numBoss = "+";
    for (int i = 11; i < 23; i++) {
      if (EEPROM.read(i) != 255) numBoss = numBoss + char(EEPROM.read(i));
    }
    //Serial.println(numBoss);
  }

  // Получить numMaster.
  numMaster = "+";
  for (int i = 25; i < 37; i++) {
    if (EEPROM.read(i) != 255) numMaster = numMaster + char(EEPROM.read(i));
  }
  if (numMaster == "")numMaster = "+7123456789";

  // Получение пароля.
  if (EEPROM.read(40) > 250) {}
  else {
    SMSpass = "";
    SMSpass = SMSpass + char(EEPROM.read(40)) + char(EEPROM.read(41)) + char(EEPROM.read(42));
    //Serial.println(SMSpass);
  }

  // Получение даты смерти.
  workYear = EEPROM.read(67);
  workMonth = EEPROM.read(68);

  // Получение состояния контура защиты.
  oldAlarm = EEPROM.read(69);
  if (oldAlarm > 1) EEPROM.write(69, 0);

  // нулевое значение АЦП
  long acpNolMlad = EEPROM.read(0); long acpNolMed = EEPROM.read(1); long acpNolStar = EEPROM.read(2);
  acpNolStar = acpNolStar << 16;
  acpNolMed = acpNolMed << 8;
  acpNol = acpNolStar + acpNolMed + acpNolMlad;

  // Получение коэфф весов.
  acpNolMlad = EEPROM.read(55); //младший байт
  acpNolMed = EEPROM.read(56); //средний
  acpNolStar = EEPROM.read(57); //самый старший
  acpNolStar = acpNolStar << 16;
  acpNolMed = acpNolMed << 8;
  setScale = acpNolStar + acpNolMed + acpNolMlad;


  // получение разрешения отправки СМС в 23 часа
  perm23 = EEPROM.read(51);

  GSMm.begin(9600);
  scale.power_up(); // включить питание весов.

  //Serial.println("DHDH");
  //Serial.println(workMonth);
  //Serial.println(workYear);

  // Инициализация GSMm на СМС SIM900
  delay(1000);
  GSMm.print("AT+CMGF=1\r"); delay(300); GSMRead();
  GSMm.print("AT+IFC=1, 1\r"); delay(300); GSMRead();
  GSMm.print("AT+CPBS=\"SM\"\r"); delay(300); GSMRead();
  GSMm.print("AT+CNMI=1,2,2,1,0\r"); delay(300); GSMRead();
  GSMm.print("AT+CMGD=1,4\r"); delay(300); GSMRead();

  newSet();
  lcd.clear();
  watchdogOn(); // Turn on the watch dog timer.

  lcd.createChar(0, b100); // делаем символ антенки
}

void alarmSMS(String numTel) { // функция отправки аварийного СМС.
  delay(1000);
  GSMm.print("AT+CMGF=1\r\n"); delay(500);
  GSMm.print("AT+CMGS=\""); GSMm.print(numTel); GSMm.print("\"\r\n");
  delay(1500);
  GSMm.print(VERPOS); GSMm.print("\r\n"); // Заголовок.
  GSMm.print("ALARM\r\n");
  GSMm.print("Bec "); GSMm.print(Weight); GSMm.print("\r\n");// Вес.
  GSMm.print("Perimetr "); GSMm.print(!oldAlarm); GSMm.print("\r\n");// Контур.
  GSMm.print("Akkum "); GSMm.print(uSr); // Напряжение питания.
  delay(100);
  GSMm.print((char)26); // символ <ctrl-z> (ASCII character 26)
}

void newSet() { // Сброс таймеров.
  setArduino = millis() / 1000; // Время удержания Arduino.
}

void setNewScale() { // Вычисление нового коэффициента весов.
  setScale = (etalonWeight - acpNol) / enterWeight;
  if (setScale < 1000) setScale = 33000; // Контроль неправильного взвешивания.
}

void modulUp() { //включить все модули, провети инициализацию.
  Serial.begin(9600);
  pinMode(13, OUTPUT); digitalWrite(13, HIGH); delay(500);
  lcd.init();
  lcd.backlight();
  Wire.begin();
  GSMm.begin(9600);
  scale.power_up();
  newSet();
  interNet=0;
}

// функция калибровки весов по весу эталона (человека).
void calibrating() {
  boolean perm;
  lcd.clear(); lcd.setCursor(0, 0); lcd.print("Set etalon"); //lcd.print("\xa8""oc""\xbf""a""\xb3\xc4\xbf""e ""\xc5\xbf""a""\xbb""o""\xbd"); //Поставьте эталон
  lcd.setCursor(0, 1); lcd.print("press key"); //lcd.print("   ""\xbd""a""\xb6\xbc\xb8\xbf""e..."); //нажмите...
  long sstart = millis() / 1000;
  while (digitalRead(2) == !keyType) {
    if ((millis() / 1000 - sstart) > 30) asm volatile ("  jmp 0");
  }
  lcd.clear(); //lcd.setCursor(0, 0); lcd.print(""); //lcd.print("   B""\xc3\xc0\xb8""c""\xbb\xc7""e""\xbc"","); //Вычисляем,
  lcd.setCursor(5, 0); lcd.print("wait"); //lcd.print("    ""\xb6\xe3\xb8\xbf""e..."); //ждите...
  long scaleEtalon = scale.read_average(100);
  lcd.clear();
  // Записать данные весов эталона в ПЗУ
  unsigned char b[3];
  b[0] = (scaleEtalon & 0x000000FF);       byte a0 = b[0];
  b[1] = (scaleEtalon & 0x0000FF00) >> 8;  byte a1 = b[1];
  b[2] = (scaleEtalon & 0x00FF0000) >> 16; byte a2 = b[2];
  EEPROM.write(3, a0);
  EEPROM.write(4, a1);
  EEPROM.write(5, a2);

  // Проверка разницы веса эталона и нулевого веса.
  // Получение данных веса порожней платформы.
  long acpNolMlad = EEPROM.read(0); //младший байт
  long acpNolMed = EEPROM.read(1); //средний
  long acpNolStar = EEPROM.read(2); //самый старший
  acpNolStar = acpNolStar << 16;
  acpNolMed = acpNolMed << 8;
  acpNol = acpNolStar + acpNolMed + acpNolMlad;

  if ((scaleEtalon - acpNol) < 400000) {
    lcd.clear();
    lcd.setCursor(0, 0); lcd.print("     Error 01     ");
    lcd.setCursor(0, 1); lcd.print("  rebooting..   ");
    delay(10000);
    asm volatile ("  jmp 0"); // программный ребут.
  }

  // Ввод веса эталона
  // Получение введенного веса.
  long vesCel = EEPROM.read(6);
  enterWeight = vesCel;
  if (enterWeight > 199)enterWeight = 199;
  if (enterWeight < 10 )enterWeight = 10;

  lcd.clear(); lcd.setCursor(0, 0); lcd.print("Write weight");//lcd.print("  ""\xa9\xba""a""\xb6\xb8\xbf""e ""\xb3""ec"); //Укажите вес
  enterWeight1 = enterWeight / 100;
  enterWeight2 = (enterWeight - enterWeight1 * 100) / 10;
  enterWeight3 = enterWeight - enterWeight1 * 100 - enterWeight2 * 10;
  lcd.setCursor(7, 1);
  lcd.print(enterWeight1);
  lcd.print(enterWeight2);
  lcd.print(enterWeight3);
  int digInd = 1;
  long startTime = millis() / 1000;
  int charLight = 1;
  // Ввод веса.
  while ((startTime + 15) > (millis() / 1000)) {
    // Моргание
    lcd.setCursor(6 + digInd, 1);
    if (charLight == 1) {
      lcd.print("\x14");
      charLight = 0;
    }
    else {
      if (digInd == 1)lcd.print(enterWeight1);
      if (digInd == 2)lcd.print(enterWeight2);
      if (digInd == 3)lcd.print(enterWeight3);
      charLight = 1;
    }
    if (digitalRead(2) != keyType) perm = 0;
    // цикл перебора цифры
    long PPP = millis();
    //boolean perm = 0; // разрешение вывалиться из цикла
    while ((PPP + 300) > millis() & perm == 0) {
      // Перебор цифр при нажатии.
      if (digitalRead(2) == keyType) {
        delay(50);
        // Зажечь цифру если выключена
        if (charLight == 0) {
          lcd.setCursor(6 + digInd, 1);
          if (digInd == 1)lcd.print(enterWeight1);
          if (digInd == 2)lcd.print(enterWeight2);
          if (digInd == 3)lcd.print(enterWeight3);
          charLight = 1;
        }
        // Ожидание удерживаемой клавиши
        long st1 = millis() / 1000;
        while (digitalRead(2) == keyType)
        {
          delay(50);
          if ((millis() / 1000) > (st1 + 3)) // Если держим более 3-х сек перейти на другую цифру.
          {
            if (digInd == 3) {
              perm = 1;
              digInd = 1;
              break;
            }
            else {
              perm = 1;
              digInd++;
              break;
            }
          }
        }
        if (perm == 1) break;
        // Граница переключения знакомест.
        if (digInd == 1) {
          if (enterWeight1 == 1) enterWeight1 = 0;
          else enterWeight1++;
          perm = 1; startTime = millis() / 1000;
        }
        if (digInd == 2) {
          if (enterWeight2 == 9) enterWeight2 = 0;
          else enterWeight2++;
          perm = 1; startTime = millis() / 1000;
        }
        if (digInd == 3) {
          if (enterWeight3 == 9) enterWeight3 = 0;
          else enterWeight3++;
          perm = 1; startTime = millis() / 1000;
        }
      }
    }
  }
  enterWeight = enterWeight1 * 100 + enterWeight2 * 10 + enterWeight3;
  if (enterWeight > 199)enterWeight = 199;
  if (enterWeight < 10 )enterWeight = 10;
  EEPROM.write(6, enterWeight);

  // Рассчет коэффициента весов.
  setScale = (scaleEtalon - acpNol) / enterWeight;
  long tempLong = setScale;

  // Записать данные коэфф весов в ПЗУ.
  b[3];
  b[0] = (tempLong & 0x000000FF);       a0 = b[0];
  b[1] = (tempLong & 0x0000FF00) >> 8;  a1 = b[1];
  b[2] = (tempLong & 0x00FF0000) >> 16; a2 = b[2];
  EEPROM.write(55, a0);
  EEPROM.write(56, a1);
  EEPROM.write(57, a2);
  asm volatile ("  jmp 0"); // программный ребут.
}


void GSMRead() { // Чтение потока данный от GSM модуля.
  clearBufferArray();              // call clearBufferArray function to clear the storaged data from the array
  count = 0; currStr = "";
  if (GSMm.available()) { // if date is comming from softwareserial port ==> data is comming from GSMm shield
    while (GSMm.available()) { // reading data into char array
      buffer2[count++] = GSMm.read();   // writing data into array
      if (count == 64) break;
      currStr += String(buffer2[count - 1]);
    }
    //Serial.println(currStr);
  }
}

void sendSMS00(String numTel, boolean full) {
  lcd.backlight();
  if (BLOCK == 0) {
    GSMm.print("AT+CMGF=1\r\n"); delay(500);
    GSMm.print("AT+CMGS=\""); GSMm.print(numTel); GSMm.print("\"\r\n");
    // отправляем смс
    delay(200);
    // Текст СМС.
    if (full == 1) {
      GSMm.print(VERPOS);  // Заголовок.
      GSMm.print("\r\n");
    }

    // Получение прошлого веса
    byte oldCel = EEPROM.read(58); //целое
    byte oldDrob = EEPROM.read(59); //дробное
    float oldDrobF = oldDrob;
    float Weight5 = 0;
    if (oldDrob > 99) {
      Weight5 = -(oldCel + ((oldDrobF - 100) / 100));
    }
    else {
      Weight5 = oldCel + (oldDrobF / 100);
    }

    oldCel = EEPROM.read(61); //целое
    oldDrob = EEPROM.read(62); //дробное
    oldDrobF = oldDrob;
    float Weight14 = 0;
    if (oldDrob > 99) {
      Weight14 = (oldCel + ((oldDrobF - 100) / 100)) * (-1);
    }
    else {
      Weight14 = oldCel + (oldDrobF / 100);
    }

    oldCel = EEPROM.read(64); //целое
    oldDrob = EEPROM.read(65); //дробное
    oldDrobF = oldDrob;
    float Weight23 = 0;
    if (oldDrob > 99) {
      Weight23 = (oldCel + ((oldDrobF - 100) / 100)) * (-1);
    }
    else {
      Weight23 = oldCel + (oldDrobF / 100);
    }

    GSMm.print("Bec"); GSMm.print("\r\n");
    GSMm.print(Weight5); GSMm.print("\r\n");
    GSMm.print(Weight14); GSMm.print("\r\n");
    GSMm.print(Weight23); GSMm.print("\r\n");
    GSMm.print("Akkum  "); GSMm.print(uSr); GSMm.print("\r\n");// Текущее напряжение.
    delay(200);
    GSMm.print((char)26); // символ <ctrl-z> (ASCII character 26)
  }
}

void sendBaseSMS(String numTel, boolean full) { // функция отправки базового СМС.
  lcd.backlight();
  if (BLOCK == 0) {

  delay(1000);

  GSMm.print("AT+CMGF=1\r\n"); delay(500);
  GSMm.print("AT+CMGS=\""); GSMm.print(numTel); GSMm.print("\"\r\n");
  // отправляем смс
  delay(200);
  // Текст СМС.
  if (full == 1) {
    GSMm.print(VERPOS);  // Заголовок.
    GSMm.print("\r\n");
  }
  GSMm.print("Bec "); GSMm.print(Weight); GSMm.print("\r\n");// Вес.
  GSMm.print("Akkum "); GSMm.print(uSr); GSMm.print("\r\n");// Текущее напряжение.
  GSMm.print("Temp "); GSMm.print(temperature); GSMm.print("\r\n");// Температура.
  GSMm.print("Antn "); GSMm.print(GSMLevel); GSMm.print("\r\n");// Температура.
  delay(200);
  GSMm.print((char)26); // символ <ctrl-z> (ASCII character 26)

  //Serial.println("sent base");
}
}

void sendSMS(String numTel, String text) {
  lcd.backlight(); delay(1000);
  GSMm.print("AT+CMGF=1\r\n"); delay(500);
  GSMm.print("AT+CMGS=\""); GSMm.print(numTel); GSMm.print("\"\r\n");
  // отправляем смс
  delay(200);
  // Текст СМС.
  GSMm.print(text); // Весь текст СМС.
  delay(200);
  GSMm.print((char)26); // символ <ctrl-z> (ASCII character 26)
  //Serial.println("sent SMS");
}

void sendSetNumMasterSMS(String numTel) { // функция отправки СМС о смене numMaster
  GSMm.print("AT+CMGF=1\r\n"); delay(500);
  GSMm.print("AT+CMGS=\""); GSMm.print(numTel); GSMm.print("\"\r\n");
  // отправляем смс
  delay(200);
  // Текст СМС.
  GSMm.print(VERPOS); GSMm.print("\r\n");// Заголовок.
  GSMm.print("Set number: "); GSMm.print(numMaster);
  delay(100);
  GSMm.print((char)26); // символ <ctrl-z> (ASCII character 26)
}

void setSleepMode() {
  while (true) {
    wdt_reset();
    lcd.clear();
    lcd.setCursor(0, 0); lcd.print("Sleep mode"); //lcd.print("Pe""\xb6\xb8\xbc"" c""\xbd""a"); //Режим сна
    lcd.setCursor(0, 1);
    if (goodNight == 1) lcd.print("YES   "); //lcd.print("   ""\xe0""A""           "); // ДА
    else lcd.print("    NO"); // НЕТ
    delay(100);
    int sstart = millis() / 1000;
    while (digitalRead(keyPin) == !keyType) {
      wdt_reset();
      if ((millis() / 1000 - sstart) > 10) asm volatile ("  jmp 0");
    }
    if (digitalRead(keyPin) == keyType) {
      goodNight = !goodNight;
      delay(500);
      EEPROM.write(50, goodNight);
    }
  }
}

void setAlarmMode() {
  while (true) {
    wdt_reset();
    lcd.clear();
    lcd.setCursor(0, 0); lcd.print("ALARM mode"); //lcd.print("Pe""\xb6\xb8\xbc"" ALARM"); //Режим ALARM
    lcd.setCursor(0, 1);
    if (ALARM) lcd.print("YES   ");//lcd.print("           ""\xe0""A""   "); // ДА
    else lcd.print("    NO"); // НЕТ
    delay(100);
    int sstart = millis() / 1000;
    while (digitalRead(keyPin) == !keyType) {
      wdt_reset();
      if ((millis() / 1000 - sstart) > 10) asm volatile ("  jmp 0");
    }
    if (digitalRead(keyPin) == keyType) {
      ALARM = !ALARM;
      EEPROM.write(54, ALARM);
      if (digitalRead(4) == HIGH) {
        EEPROM.write(69, 1);
        oldAlarm = 1;
      } else {
        EEPROM.write(69, 0);
        oldAlarm = 0;
      }
      delay(500);
    }
  }
}

void setToZero() { // функция выполнения обнуления

  boolean zero = 0;
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("    Set zero    ");// Обнуление
  int sstart = millis() / 1000;
  while (true) {
    lcd.setCursor(0, 1);
    if (zero == 1) lcd.print("   YES          "); // ДА
    else lcd.print("         no     "); // НЕТ
    delay(100);
    if ((millis() / 1000 - sstart) > 5) break;//asm volatile ("  jmp 0");
    if (digitalRead(2) == keyType) {
      zero = !zero;
      sstart = millis() / 1000;
      delay(200);
    }
  }
  // Отказ от обнуления
  if (zero == 0) {
    asm volatile ("  jmp 0");
  }
  else {
  
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("Set PLATFORM"); //lcd.print("\xa9""c\xbf""a\xbd""o\xb3\xb8\xbf""e"); //Установите
  //lcd.setCursor(0, 1); lcd.print("\xbe\xbb""a\xbf\xe4""op\xbc""y "); //платформу
  for (int i = 0; i < 300; i++) {
    wdt_reset();
    lcd.setCursor(14, 1); lcd.print(30 - i / 10); lcd.print(" ");
    delay(100);
    if (digitalRead(keyPin) == keyType) break;
  }
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("Go to zero"); //lcd.print("O\xb2\xbd""y\xbb""e""\xbd\xb8""e..."); // обнуление
  int i;
  acpNol = 0;
  for (i = 0; i < 100; i++) {
    wdt_reset();
    acpNol = acpNol + scale.read();
    lcd.setCursor(10, 1);
    lcd.print(i + 1);
    lcd.print(" % ");
  }
  acpNol = acpNol / i;
  delay(1000);
  unsigned long scaleData = acpNol;
  unsigned char bytes[3];
  bytes[0] = (scaleData & 0x000000FF);  byte acpNol0 = bytes[0];
  bytes[1] = (scaleData & 0x0000FF00) >> 8;  byte acpNol1 = bytes[1];
  bytes[2] = (scaleData & 0x00FF0000) >> 16;  byte acpNol2 = bytes[2];
  EEPROM.write(0, acpNol0); EEPROM.write(1, acpNol1); EEPROM.write(2, acpNol2);
  lcd.clear();
  predWeight = 0;
}
}

void clearBufferArray() {
  for (int i = 0; i < count; i++) {
    buffer2[i] = NULL;
  }
}

// Вывод версии.
void ver() {
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("www.BeeLove.pro");
  lcd.setCursor(0, 1); lcd.print(VERPOS);
  for (int i = 0; i < 300; i++) {
    wdt_reset();
    //lcd.setCursor(14, 1); lcd.print(30 - i / 10); lcd.print(" ");
    delay(100);
    if (digitalRead(keyPin) == keyType) break;
  }
}

void goToSleep() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode.
  sleep_enable(); // Enable sleep mode.
  sleep_mode(); // Enter sleep mode.
  sleep_disable(); // Disable sleep mode after waking.
  //lcd.createChar(0, b100); // делаем символ антенки
}

void watchdogOn() {
  MCUSR = MCUSR & B11110111;
  WDTCSR = WDTCSR | B00011000;
  WDTCSR = B00100001;
  WDTCSR = WDTCSR | B01000000;
  MCUSR = MCUSR & B11110111;
}

ISR(WDT_vect)
{
  sleep_count ++; // keep track of how many sleep cycles
  if (digitalRead(keyPin) == keyType)
  {
    //asm volatile ("jmp 0");
    sleep_count = sleep_total;
  }
}

void setToDefault() {
  // Записать данные коэфф весов в ПЗУ.
  long tempLong = 22995;
  unsigned char b[3];
  b[0] = (tempLong & 0x000000FF);       byte a0 = b[0];
  b[1] = (tempLong & 0x0000FF00) >> 8;  byte a1 = b[1];
  b[2] = (tempLong & 0x00FF0000) >> 16; byte a2 = b[2];
  EEPROM.write(55, a0);
  EEPROM.write(56, a1);
  EEPROM.write(57, a2);

  // Сброс почасовых данных.
  EEPROM.write(58, 0); EEPROM.write(59, 0); EEPROM.write(61, 0); EEPROM.write(62, 0); EEPROM.write(64, 0); EEPROM.write(65, 0);
  //Serial.println("setTime");
  // Установка времени
  // RTC.adjust(DateTime(year, month, dayOfMonth, hour, minute, 1));
  //RTC.adjust(DateTime(year, month, dayOfMonth, 14, 00, 1));
  RTC.adjust(DateTime(2015, 12, 24, 20, 59, 20));
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("     Set to     ");
  lcd.setCursor(0, 1); lcd.print("    default..   ");
  delay(2000);
  //asm volatile ("  jmp 0"); // программный ребут.
}

/*=========================================================================================================
Совсем все.


Недокументированные функции:

== Смена номера Boss.
   Послать СМС "BOSS"
   Отклик установленный номер босса.

== Установка даты смерти весов.
   Послать СМС "DH0199" - разблокировка.
   Отклик СМС с отчетом в полночь.
   */
