SIM800L mini

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Общий вид контроллера со снятой крышкой.

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

В корпусе установлен модуль питания ~220v -> 5V 3A.
Мощности модуля питания достаточно для питания ARDUINO Nano и модема SIM800L.

Поскольку питание каждого из модулей осуществляется от одного источника +5В, а SIM800L требует 4В, то запитка последнего осуществляется через 2 последовательно включенных диода, рассчитанных на ток 2 А. 
Параллельно выводу питания SIM800L подключены 4 электролитических конденсатора 1000 мкФ х 6.3 В.
В этом случае обеспечивается стабильная связь SIM800L с базовой станцией.

 Все протестировано с помощью АТ команд. Модуль подтвердил исправность и стабильную работу.

Содержимое скетча для тестирования не привожу, поскольку подобное было рассмотрено на этом форуме.
 

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Для надежной связи с базовой станцией антенна модема SIM800L вынесена наружу и закреплена на боковой стенке. Отрицательный вывод модуля питания соединен с металлическим корпусом контроллера.

                                         

                              

 

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

-

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

   Вот тут начались танцы с бубном...

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

   Признаком отказа системы отопления является падение температуры трубы для вывода топочных газов.
   При штатном режиме работы отопления эта температура изменяется в диапазоне +45 - +65 °С.
   Температура измеряется с помощью DS 18b20. Проблем кодом не оказалось...
   По запросу текущую температуру получаю СМС -кой на мой телефон. 

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

 

 // Все работает !!!
// С мобильного телефона можем отправлять SMS сообщения следующего вида 001 ....... 99999 итого 100000 комбинаций....
// С мобильного телефона можем отправлять SMS сообщения следующего вида *100# и другие 
/* 
На базе этого скетча попытаемся написать код управления для мониторинга текущей температуры датчика,
для отправки СМС на мой смартфон в случае потухания котла,
для получения баланса СИМ карты  МТС Беларусь. СИМ-ка установлена в слоте SIM800L.
*/
 
#include <SoftwareSerial.h>                                   // Библиотека програмной реализации обмена по UART-протоколу
SoftwareSerial SIM800(8, 9);                                  // RX, TX
 
// int pins[3] = {5, 6, 7};                                      // Пины с подключенными светодиодами
 
String _response    = "";                                     // Переменная для хранения ответа модуля
long lastUpdate = millis();                                   // Время последнего обновления
long updatePeriod   = 60000;                                  // Проверять каждую минуту
 
String phones = "+37529-------";                              // Белый список телефонов - Это мой мобильник A1
 
void setup() 
{
  
  Serial.begin(9600);                                         // Скорость обмена данными с компьютером
  SIM800.begin(9600);                                         // Скорость обмена данными с модемом
  Serial.println("Start!");
 
  sendATCommand("AT", true);                                  // Отправили AT для настройки скорости обмена данными
  sendATCommand("AT+CMGDA=\"DEL ALL\"", true);                // Удаляем все SMS, чтобы не забивать память
 
  // Команды настройки модема при каждом запуске
  _response = sendATCommand("AT+CLIP=1", true);               // Включаем АОН
  _response = sendATCommand("AT+DDET=1", true);               // Включаем DTMF
  sendATCommand("AT+CMGF=1;&W", true);                        // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  lastUpdate = millis();                                      // Обнуляем таймер
}
 
String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                                              // Переменная для хранения результата
  Serial.println(cmd);                                            // Дублируем команду в монитор порта
  SIM800.println(cmd);                                            // Отправляем команду модулю
  if (waiting) {                                                  // Если необходимо дождаться ответа...
  _resp = waitResponse();                                         // ... ждем, когда будет передан ответ
                                                                  // Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
    if (_resp.startsWith(cmd)) {                                  // Убираем из ответа дублирующуюся команду
      _resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
    }
    Serial.println(_resp);                                        // Дублируем ответ в монитор порта
  }
  return _resp;                                                   // Возвращаем результат. Пусто, если проблема
}
 
String waitResponse() {                                           // Функция ожидания ответа и возврата полученного результата
  String _resp = "";                                              // Переменная для хранения результата
  long _timeout = millis() + 5000;                                // Переменная для отслеживания таймаута (5 секунд)
  while (!SIM800.available() && millis() < _timeout)  {};         // Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
  if (SIM800.available()) {                                       // Если есть, что считывать...
    _resp = SIM800.readString();                                  // ... считываем и запоминаем
  }
  else {                                                          // Если пришел таймаут, то...
    Serial.println("Timeout...");                                 // ... оповещаем об этом и...
  }
  return _resp;                                                   // ... возвращаем результат. Пусто, если проблема
}
 
bool hasmsg = false;                                              // Флаг наличия сообщений к удалению
void loop() {
  if (lastUpdate + updatePeriod < millis() ) {                    // Пора проверить наличие новых сообщений
    do {
      _response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений
      if (_response.indexOf("+CMGL: ") > -1) {                    // Если есть хоть одно, получаем его индекс
        int msgIndex = _response.substring(_response.indexOf("+CMGL: ") + 7, _response.indexOf("\"REC UNREAD\"", _response.indexOf("+CMGL: ")) - 1).toInt();
        char i = 0;                                               // Объявляем счетчик попыток
        do {
          i++;                                                    // Увеличиваем счетчик
          _response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true);  // Пробуем получить текст SMS по индексу
          _response.trim();                                       // Убираем пробелы в начале/конце
          if (_response.endsWith("OK")) {                         // Если ответ заканчивается на "ОК"
            if (!hasmsg) hasmsg = true;                           // Ставим флаг наличия сообщений для удаления
            sendATCommand("AT+CMGR=" + (String)msgIndex, true);   // Делаем сообщение прочитанным
            sendATCommand("\n", true);                            // Перестраховка - вывод новой строки
            parseSMS(_response);                                  // Отправляем текст сообщения на обработку
            break;                                                // Выход из do{}
          }
          else {                                                  // Если сообщение не заканчивается на OK
            Serial.println ("Error answer");                      // Какая-то ошибка
            sendATCommand("\n", true);                            // Отправляем новую строку и повторяем попытку
          }
        } while (i < 10);
        break;
      }
      else {
        lastUpdate = millis();                                    // Обнуляем таймер
        if (hasmsg) {
          sendATCommand("AT+CMGDA=\"DEL READ\"", true);           // Удаляем все прочитанные сообщения
          hasmsg = false;
        }
        break;
      }
    } while (1);
  }
 
  if (SIM800.available())   {                                     // Если модем, что-то отправил...
    _response = waitResponse();                                   // Получаем ответ от модема для анализа
    _response.trim();                                             // Убираем лишние пробелы в начале и конце
    Serial.println(_response);                                    // Если нужно выводим в монитор порта
    if (_response.indexOf("+CMTI:")>-1) {                         // Пришло сообщение об отправке SMS
      lastUpdate = millis() -  updatePeriod;                      // Теперь нет необходимости обрабатывать SMS здесь, достаточно просто
                                                                  // сбросить счетчик автопроверки и в следующем цикле все будет обработано
    }
  }
  if (Serial.available())  {                                      // Ожидаем команды по Serial...
    SIM800.write(Serial.read());                                  // ...и отправляем полученную команду модему
  };
}
 
void parseSMS(String msg) {                                       // Парсим SMS
  String msgheader  = "";
  String msgbody    = "";
  String msgphone   = "";
 
  msg = msg.substring(msg.indexOf("+CMGR: "));
  msgheader = msg.substring(0, msg.indexOf("\r"));                // Извлекаем номер телефона отправившего СМС запрос
 
  msgbody = msg.substring(msgheader.length() + 1);                // не менять
  msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK"));      // Извлекаем текст SMS
  msgbody.trim();
  //Serial.println();
  int firstIndex = msgheader.indexOf("\",\"") + 3;                // не менять
  int secondIndex = msgheader.indexOf("\",\"", firstIndex);
  msgphone = msgheader.substring(firstIndex, secondIndex);
 
  Serial.println("Phone: " + msgphone);                           // Выводим номер телефона
  Serial.println("Message: " + msgbody);                          // Выводим текст SMS
 
  if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1)     // Если телефон в белом списке, то...
  {   
    // ===================================================================================================================================== 
       sendSMS(phones, "Полученная СМС - ка:"+msgbody );              //ОТПРАВКА НА БЕЛЫЕ ТЕЛЕФОНЫ РЕЗУЛЬТАТА ВЫПОЛНЕНИЯ КОМАНДЫ !!!!!!! 
 
  // =====================================================================================================================================
  }
  else {
    Serial.println("Unknown phonenumber");
    }
}      // ============================================   End void parseSMS(String msg)  ==================================================
 
 
void sendSMS(String phone, String message)
{ 
  sendATCommand("AT+CMGF=1", true);                               // Включаем текстовый режима SMS (Text mode)
  sendATCommand("AT+CMGS=\"" + phone + "\"", true);               // Переходим в режим ввода текстового сообщения
  sendATCommand(message + "\r\n" + (String)((char)26), true);     // После текста отправляем перенос строки и Ctrl+Z
}

 

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

   


 // ЭТО УЖЕ РАБОТАЕТ !!!
  #include <SoftwareSerial.h>                             // Библиотека програмной реализации обмена по UART-протоколу
  SoftwareSerial SIM800(8, 9);                            // RX, TX
  String _response = "";                                  // Переменная для хранения ответа модуля
  String _phone_to_SMS = "+375---------";                 // Сюда пишем свой номер телефона в международном формате
  void setup() {
  Serial.begin(9600);                                     // Скорость обмена данными с компьютером
  SIM800.begin(9600);                                     // Скорость обмена данными с модемом
  Serial.println("Start!");

  sendATCommand("AT", true);                              // Отправили AT для настройки скорости обмена данными

  // Команды настройки модема при каждом запуске
  _response = sendATCommand("AT+CLIP=1", true);           // Включаем АОН
  //_response = sendATCommand("AT+DDET=1", true);         // Включаем DTMF
  _response = sendATCommand("AT+CMGF=1", true);           // Включаем текстовый режим SMS (Text mode)
  _response = sendATCommand("AT+CUSD=1,\"*100#\"", true); // Здесь необходимо указать свой USSD-запрос
}

String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                                      // Переменная для хранения результата
  Serial.println(cmd);                                    // Дублируем команду в монитор порта
  SIM800.println(cmd);                                    // Отправляем команду модулю
  if (waiting) {                                          // Если необходимо дождаться ответа...
    _resp = waitResponse();                               // ... ждем, когда будет передан ответ
                                                          // Если Echo Mode выключен (ATE0), то эти 3 строки можно закоментировать
    if (_resp.startsWith(cmd)) {                          // Убираем из ответа дублирующуюся команду
      _resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
    }
    Serial.println(_resp);                                // Дублируем ответ в монитор порта
  }
  return _resp;                                           // Возвращаем результат. Пусто, если проблема
}

String waitResponse() {                                   // Функция ожидания ответа и возврата полученного результата
  String _resp = "";                                      // Переменная для хранения результата
  long _timeout = millis() + 5000;                        // Переменная для отслеживания таймаута (5 секунд)
  while (!SIM800.available() && millis() < _timeout)  {}; // Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
  if (SIM800.available()) {                               // Если есть, что считывать...
    _resp = SIM800.readString();                          // ... считываем и запоминаем
  }
  else {                                                  // Если пришел таймаут, то...
    Serial.println("Timeout...");                         // ... оповещаем об этом и...
  }
  return _resp;                                           // ... возвращаем результат. Пусто, если проблема
}
                  // ==================  Цикл void loop ========================
void loop() {                                                                                                                                          //=
  if (SIM800.available())   {                             // Если модем, что-то отправил...                                                              =
    _response = waitResponse();                           // Получаем ответ от модема для анализа                                                        =
    _response.trim();                                     // Убираем лишние пробелы в начале и конце                                                     =
    Serial.println(_response);                            // Если нужно выводим в монитор порта                                                          =
    //....                                                                                                                                               =
    if (_response.startsWith("+CUSD:")) {                  // Пришло уведомление о USSD-ответе                                                 =
      if (_response.indexOf("\"") > -1) {          // Если ответ содержит кавычки, значит есть сообщение                               =
                                                                     //(предохранитель от "пустых" USSD-ответов)                               =
        String msgBalance = _response.substring(_response.indexOf("\"") + 2);  // Получаем непосредственно текст                          =
        msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));                                                                 //=
        Serial.println("USSD: " + msgBalance);            // Выводим полученный USSD-ответ                                                     =
                                                                                                                                                       //=
       float balance = getFloatFromString(msgBalance);    // Извлекаем информацию о балансе                                                              =
                                                                                                                                                       //= 
    Serial.println("\r\nBalance: " + (String)balance );   // Выводим информацию о балансе                                                      =
        sendSMS(_phone_to_SMS, "\r\nBalance: " + (String)balance);                                                                           //=
      }                                                                                                                                                //=
    }                                                                                                                                                  //=
  }                                                                                                                                                    //=
   if (Serial.available())  {                    // Ожидаем команды по Serial...                                                                       //=
    SIM800.write(Serial.read());                // ...и отправляем полученную команду модему                                                           //=
  };                                                                                                                                                   //=
}      //========================================================================

void sendSMS(String phone, String message)
{
  String _result = "";
  sendATCommand("AT+CMGF=1", true);                                         // Включаем текстовый режима SMS (Text mode)
  sendATCommand("AT+CMGS=\"" + phone + "\"", true);                         // Переходим в режим ввода текстового сообщения
  _result = sendATCommand(message + (String)((char)26), true);              // После текста отправляем перенос строки и Ctrl+Z
}

float getFloatFromString(String str) {                                      // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
  bool   flag     = false;
  String result   = "";
  str.replace(",", ".");                                                    // Если в качестве разделителя десятичных используется запятая - меняем её на точку.
  for (int i = 0; i < str.length(); i++) {
    if (isDigit(str[i]) || (str[i] == (char)46 && flag)) {                  // Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания),
      if (result == "" && i > 0 && (String)str[i - 1] == "-") {             // Нельзя забывать, что баланс может быть отрицательным
        result += "-";                                                      // Добавляем знак в начале
      }
      result += str[i];                                                     // начинаем собирать их вместе
      if (!flag) flag = true;                                               // Выставляем флаг, который указывает на то, что сборка числа началась.
    }
    else  {                                                                 // Если цифры закончились и флаг говорит о том, что сборка уже была,
      if (str[i] != (char)32) {                                             // Если порядок числа отделен пробелом - игнорируем его, иначе...
        if (flag) break;                                                    // ...считаем, что все.
      }
    }
  }
  return result.toFloat();                                                  // Возвращаем полученное число.
}
wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

    Поскольку домик находится в 150 км от Минска, то возникла необходимость проверка текущего баланса на счету. Приведенный выше скетч с этой задачей справляется.

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

   Должен сказать, что приведенные выше тексты написаны не мною. Эти тексты взяты на Codius.ru и мною адаптированы под решаемую задачу. Должен сказать о хорошем качестве выложенной информации на этом сайте. Все выложенные примеры работоспособны.

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

   Эти скетчи каждый  сам по себе работают.
Первый скетч возвращает посланное в контроллер сообщение на телефон. 
Второй скетч высылает баланс, актуальный в данный момент времени.
Попытки все объединить в один скетч к успеху не привели. 
К тому же нужно прописать реагирование на 2 ситуации - снижение температуры ниже 40 °С и  наступление момента отрицательного баланса. Белорусский МТС позволяет иметь небольшой отрицательный баланс.

Прошу сообщество оказать мне помощь в решении проблемы. Нужны советы и работающие примеры.
В принципе с этой задачей могу справиться сам. Но возраст почти 70 лет и не очень хорошее знание С++ не способствуют быстрому решению этой задачи... 

Другое дело помочь сделать 3D модель корпуса для электронных поделок, которые можно распечатать на 3D принтере... Или сделать рабочие чертежи, используя разработанную 3D модель...
Этим владею на уровне эксперта и обучаю этому студентов БГУ.

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Вот работающее решение. Вывод DQ датчика DS18b20 подключен к выводу D12 Arduino nano

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 12


SoftwareSerial SIM800(8, 9);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);


const String MAIN_PHONE = "+************";       // напишите сюда свой номер в международном формате
const String PDU_USSD_BALANCE_QUERY = "AT+CUSD=1,\"*100#\""; // пишем код для своего оператора
const String TEXT_USSD_BALANCE_QUERY = "AT+CUSD=1,\"#100#\""; // пишем код для своего оператора
const String BALANCE_TEXT_QUERY = "Balance";                    // содержание СМС для получения текстового ответа на запрос о балансе             
const String BALANCE_PDU_QUERY = "Balance ussd";                // содержание СМС для получения PDU ответа на запрос о балансе
const String TEMPERATURE_QUERY = "Temperature";                 // содержание СМС для получения ответа на запрос о температуре
const String CURRENCY = " BYN";                                 // текстовое представление валюты
const float  BALANCE_TRESHOLD = 5.0;                            // нижнее пороговое значение баланса
const float  TEMPERATURE_TRESHOLD = 35.0;                       // нижнее пороговое значение температуры
bool         hasmsg = false;


String sendATCommand(const String& cmd, bool waiting) {
  String response = "";                                      // Переменная для хранения результата
  Serial.println(cmd);                                    // Дублируем команду в монитор порта
  SIM800.println(cmd);                                    // Отправляем команду модулю
  if (waiting) {                                          // Если необходимо дождаться ответа...
    response = waitResponse();                               // ... ждем, когда будет передан ответ
    if (response.startsWith(cmd)) {                          // Убираем из ответа дублирующуюся команду
      response = response.substring(response.indexOf("\r", cmd.length()) + 2);
    }
    Serial.println(response );                               // Дублируем ответ в монитор порта
  }
  return response;                                           // Возвращаем результат. Пусто, если проблема
}

String waitResponse() {                                   // Функция ожидания ответа и возврата полученного результата
  String response = "";                                      // Переменная для хранения результата
  int64_t timeout = millis() + 10000;                        // Переменная для отслеживания таймаута (5 секунд)
  while (!SIM800.available() && millis() < timeout) {}; // Ждем ответа 5 секунд, если пришел ответ или наступил таймаут, то...
  if (SIM800.available()) {                               // Если есть, что считывать...
    response = SIM800.readString();                          // ... считываем и запоминаем
  }
  else {                                                  // Если пришел таймаут, то...
    Serial.println("Timeout...");                         // ... оповещаем об этом и...
  }
  return response;                                           // ... возвращаем результат. Пусто, если проблема
}

void sendSMS(const String& phone, const String& message) {
  sendATCommand("AT+CMGS=\"" + phone + "\"", true);                         // Переходим в режим ввода текстового сообщения
  sendATCommand(message + (String)((char)26), true);                        // После текста отправляем перенос строки и Ctrl+Z
}

void getBalance() {
  sendATCommand(PDU_USSD_BALANCE_QUERY, true);
  String answer = waitResponse();
  answer.trim();
  String msgBalance = answer.substring(answer.indexOf("\"") + 1);  // Получаем непосредственно текст
  msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
  float balance = getFloatFromString(UCS2ToString(msgBalance));    // Извлекаем информацию о балансе
  sendSMS(MAIN_PHONE, "\r\nBalans SIM karty: " + (String)balance + CURRENCY + ".");
}

void alternativeGetBalance() {
  sendATCommand(TEXT_USSD_BALANCE_QUERY, true);
  String answer = waitResponse();
  answer.trim();
  if (answer.indexOf("\"") > -1) {
    String msgBalance = answer.substring(answer.indexOf("\"") + 2);
    msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
    float balance = getFloatFromString(msgBalance);
    Serial.println("\r\nBalans SIM karty: " + (String)balance);
    sendSMS(MAIN_PHONE, "\r\nBalans SIM karty: " + (String)balance + CURRENCY + ".");
  }
}

float getFloatFromString(String str) {                                      // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
  bool flag = false;
  String result = "";
  str.replace(",", ".");                                                    // Если в качестве разделителя десятичных используется запятая - меняем её на точку.
  for (size_t i = 0; i < str.length(); ++i) {
    if (isDigit(str[i]) || (str[i] == (char)46 && flag)) {                  // Если начинается группа цифр (при этом на точку без цифр не обращаем внимания),
      if (i != 0 && result == "" && (String)str[i - 1] == "-") {            // Нельзя забывать, что баланс может быть отрицательным
        result += "-";                                                      // Добавляем знак в начале
      }
      result += str[i];                                                     // начинаем собирать их вместе
      if (!flag) {
        flag = true;                                                        // Выставляем флаг, который указывает на то, что сборка числа началась.
      }
    }
    else {                                                                 // Если цифры закончились и флаг говорит о том, что сборка уже была,
      if (str[i] != (char)32) {
        if (flag) {
          break;
        }
      }
    }
  }
  return result.toFloat();                                                 // Возвращаем полученное число.
}

void parseSMS(String msg) {                                   // Парсим SMS
  String msgheader  = "";                                     // Переменная под звонивший телефона для анализа
  String msgbody    = "";                                     // Переменная под SMS
  String msgphone   = "";                                     // Переменная под номер телефона

  msg = msg.substring(msg.indexOf("+CMGR: "));
  msgheader = msg.substring(0, msg.indexOf("\r"));            // Получаем звонивший телефон

  msgbody = msg.substring(msgheader.length() + 2);
  msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK"));  // Получаем текст полученной SMS
  msgbody.trim();                                             //Обрезаем начальные или концевые символы

  int firstIndex = msgheader.indexOf("\",\"") + 3;
  int secondIndex = msgheader.indexOf("\",\"", firstIndex);
  msgphone = msgheader.substring(firstIndex, secondIndex);

  if (msgphone.length() && MAIN_PHONE.indexOf(msgphone) != -1) { // Если телефон в белом списке, то...
    if (msgbody == BALANCE_PDU_QUERY) {
      getBalance();
    }
    else if (msgbody == BALANCE_TEXT_QUERY) {
      alternativeGetBalance();
    }
    else if (msgbody == TEMPERATURE_QUERY) {
      sendSMS(MAIN_PHONE, "SENSOR TEMPERATURE = " + String(obtainTemperature()) + " C.");
    }

    Serial.println("Phone: " + msgphone);                          // Выводим номер телефона
    Serial.println("Message: " + msgbody);                         // Выводим текст SMS
  }
  else if (msgphone.length()) {
    Serial.println("Unknown phone number: " + msgphone);
    Serial.println("Message: " + msgbody);
  }
}

unsigned char HexSymbolToChar(char c) {
  if      ((c >= 0x30) && (c <= 0x39)) return (c - 0x30);
  else if ((c >= 'A') && (c <= 'F'))   return (c - 'A' + 10);
  else                                 return (0);
}

String UCS2ToString(String s) {
  String result = "";
  unsigned char c[5] = "";
  for (size_t i = 0; i < s.length() - 3; i += 4) {
    unsigned long code = (((unsigned int)HexSymbolToChar(s[i])) << 12)    +
                         (((unsigned int)HexSymbolToChar(s[i + 1])) << 8) +
                         (((unsigned int)HexSymbolToChar(s[i + 2])) << 4) +
                         ((unsigned int)HexSymbolToChar(s[i + 3]));
    if (code <= 0x7F) {
      c[0] = (char)code;
      c[1] = 0;
    } else if (code <= 0x7FF) {
      c[0] = (char)(0xC0 | (code >> 6));
      c[1] = (char)(0x80 | (code & 0x3F));
      c[2] = 0;
    } else if (code <= 0xFFFF) {
      c[0] = (char)(0xE0 | (code >> 12));
      c[1] = (char)(0x80 | ((code >> 6) & 0x3F));
      c[2] = (char)(0x80 | (code & 0x3F));
      c[3] = 0;
    } else if (code <= 0x1FFFFF) {
      c[0] = (char)(0xE0 | (code >> 18));
      c[1] = (char)(0xE0 | ((code >> 12) & 0x3F));
      c[2] = (char)(0x80 | ((code >> 6) & 0x3F));
      c[3] = (char)(0x80 | (code & 0x3F));
      c[4] = 0;
    }
    result += String((char*)c);
  }
  return (result);
}

void checkNewMessages() {
  String response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений
  if (response.indexOf("+CMGL: ") >= 0) {                    // Если есть хоть одно, получаем его индекс
    int msgIndex = response.substring(response.indexOf("+CMGL: ") + 7, response.indexOf("\"REC UNREAD\"", response.indexOf("+CMGL: ")) - 1).toInt();
    response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true);  // Пробуем получить текст SMS по индексу
    response.trim();                                       // Убираем пробелы в начале/конце
    if (response.endsWith("OK")) {                         // Если ответ заканчивается на "ОК"
      if (!hasmsg) {
        hasmsg = true;                           // Ставим флаг наличия сообщений для удаления
      }
      sendATCommand("AT+CMGR=" + (String)msgIndex, true);   // Делаем сообщение прочитанным
      sendATCommand("\n", true);                            // Перестраховка - вывод новой строки
      parseSMS(response);                                  // Отправляем текст сообщения на обработку
    }
  }
  else {
    if (hasmsg == true) {
      sendATCommand("AT+CMGDA=\"DEL READ\"", true);           // Удаляем все прочитанные сообщения
      hasmsg = false;
    }
  }
}

void modemQueryAndResponse() {
  if (SIM800.available())   {                             // Если модем что-то получил...
    String data = waitResponse();                           // Получаем ответ для модема для анализа
    data.trim();                                     // Убираем лишние пробелы в начале и конце
    parseSMS(data);
    Serial.println(data);                            // Если нужно, выводим в монитор порта
    if (data.startsWith("+CUSD:")) {                 // Пришло уведомление об USSD-ответе
      if (data.indexOf("\"") > -1) {                 // Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
        String msgBalance = data.substring(data.indexOf("\"") + 2);
        msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
        float balance = getFloatFromString(msgBalance);
        Serial.println("\r\nBalans SIM karty: " + (String)balance + CURRENCY + ".");
      }
    }
  }
  else if (Serial.available())  {                    // Ожидаем команды по Serial...
    SIM800.write(Serial.read());                // ... и отправляем полученную команду модему
  }
}

void sendTemperatureSMS(const String& current_temperature) {
  sendSMS(MAIN_PHONE, "SENSOR TEMPERATURE = " + current_temperature + " degree " + "C" + ".");
}

float obtainTemperature() {
  sensors.requestTemperatures();
  return sensors.getTempCByIndex(0);
}

void tresholdTemperature(float current_temperature) {
  static bool flag = 1;
  if (current_temperature < TEMPERATURE_TRESHOLD && flag) {
    sendSMS(MAIN_PHONE, "Temperature is less than " + String(TEMPERATURE_TRESHOLD)+ " deg C"+ " and equal to " + String(current_temperature) + " deg C.");
    flag = 0;
  }
  else if (current_temperature >= TEMPERATURE_TRESHOLD && !flag) {
    flag = 1;
  }
}

void balanceChecking() {
  static bool flag = 1;
  sendATCommand(TEXT_USSD_BALANCE_QUERY, true);
  String answer = waitResponse();
  answer.trim();
  String msgBalance = answer.substring(answer.indexOf("\"") + 2);
  msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
  float balance = getFloatFromString(msgBalance);
  Serial.println("Balance is " + String(balance));
  if (balance < BALANCE_TRESHOLD && flag) {
    sendSMS(MAIN_PHONE, "Balance is less than " + String(BALANCE_TRESHOLD) + CURRENCY + " and equal to " + String(balance) + CURRENCY + ".");
    flag = 0;
  }
  else if (balance >= BALANCE_TRESHOLD && !flag) {
    flag = 1;
  }
}

void setup() {
  Serial.begin(9600);
  SIM800.begin(9600);

  sensors.begin();
  sensors.requestTemperatures();

  Serial.println("Start!");

  sendATCommand("AT", true);
  sendATCommand("AT+CMGDA=\"DEL ALL\"", true);
  sendATCommand("AT+CLIP=1", true);
  sendATCommand("AT+CMGF=1;&W", true);

}

void loop() {
  static int64_t balance_check_timer = 0;
  static int64_t temperature_check_timer = 0;
  static int64_t new_message_check_timer = 0;

  modemQueryAndResponse();
  if (abs(millis() - new_message_check_timer) >= 10000) { // раз в десять секунд проверка входящих СМС
    checkNewMessages();
    new_message_check_timer = millis();
  }
  if (abs(millis() - temperature_check_timer) >= 60000) { // раз в минуту проверка температуры; если она меньше установленного порога, то 1 раз отправляется СМС с текущей температурой на основной номер, прописанный в скетче
    tresholdTemperature(obtainTemperature());
    temperature_check_timer = millis();
  }
  if (abs(millis() - balance_check_timer) >= 40000) {  // раз в час проверка баланса; если он меньше установленного порога, то 1 раз отправляется СМС с текущим балансом на основной номер, прописанный в скетче 
    balanceChecking();                                 // уменьшил время срабатывания для того, чтобы не ждать час, значение по умолчанию - 3600000
    balance_check_timer = millis();
  }
}

 

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Нужно изменить строку номер +100500 !

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Что Вы имеете в виду?

 

stambylov
stambylov аватар
Offline
Зарегистрирован: 10.05.2012

ПРивет, почитал сверху, решил тоже выложить рабочий обрезанный код для получения и отправки смс

Arduino Mega используется, если что

Да, еще на русском смс шлет))

Есть голая ардуина, на нее заливаете скетч, при первом запуске, она сама чистит EPPROM, т.к. не добавлен номер главного телефона(хранится он в EPPROM), далее отсылаете на номер, который вставлен в модуль SIM, "Register", в ответ получаете ответ на русском, далее разберетесь по счетчу сами, если прилепить часики реального времени, можно в определенное время проверять баланс(он и так проверяется, только по вашему запросу) и т.п.

//Библиотеки
#include <SoftwareSerial.h>
#include <EEPROM.h>
#include <Wire.h> // Wire.h
#include <OneWire.h>// библиотека для работы с протоколом 1-Wire
#include <DallasTemperature.h>// библиотека для работы с датчиком DS18B20

#define SIM800_TX_PIN 53
#define SIM800_RX_PIN 52
SoftwareSerial gsm(SIM800_TX_PIN,SIM800_RX_PIN);
#define ONE_WIRE_BUS 2      //Датчики по шине 1-wire


// создаём объект для работы с библиотекой OneWire
OneWire oneWire(ONE_WIRE_BUS);
// создадим объект для работы с библиотекой DallasTemperature
DallasTemperature sensors(&oneWire);
// создаём указатель массив для хранения адресов датчиков
DeviceAddress *sensorsUnique;
// количество датчиков на шине
int countSensors;

unsigned long currentMillis = 0;
//переменные для датчиков ТЕ по шине 1-WIRE
long lastUpdateTime1WIRE = 0; // Переменная для хранения времени последнего считывания с датчика
const int TEMP_UPDATE_TIME1WIRE = 5000; // Определяем периодичность проверок датчиков
String STemperature1 = "";
String STemperature2 = "";
String STemperature3 = "";
int StartGSM = 0;
String NBoss = "";
String NBoss1 = "";
String NBoss2 = "";
String NBoss3 = "";
String NBoss4 = "";
String NBoss5 = "";
String NBossNumber = "";
String Temp = "";
int tempZaprosBalansa = 0; // переменная, хранящая метку о запросе каждый день баланса
int tempForWaitSendSmsTE = 0;
long counter = 0;
long timerForSignalGSM = 1000000;

// Переменные для обработки смс +CSQ
int intNumberLevelFirst = 0;
int intNumberLevelSecond = 0;
int IntSignalLevel = 0;
int FlagSignal = 0;
// Переменные для чтения смс
String currStr = "";
String dataSmsN = "";
int flag1 = 0;
int flag2 = 0;
String currStrN = "";
char currSymb = 0;
String dataSms = "";
String dataBalance = "";
//String dataBalanceNumber = "";
String dataBalanceTemp = "";
String val = "";
int ch = 0;
char data = 0;
// Переменные для циклов
int i = 0;
int k = 0;
byte  s1;                          // 
byte  s2;                          // 
byte  s3;                          // 
byte  s4;                          // 
byte  s5;                          // 
byte  s6;                          // 
byte  s7;                          // 
byte  s8;                          // 
byte  s9;                          // 
byte  s10;                         // 
byte  s11;

String msgBalance = "";
float balance = 0;

int tempBalans = 0; // переменная, хранящая метку о запросе баланса
String textToSend = "";
int Boss = 0;
int BossTemp = 0;

String BalansSim = "Баланс: ";
String HelloNumberIsBoss = "Ваш номер главный: ";
String temp = "";
String _response = "";  // Переменная для хранения ответа модуля
int IntSignalLevelTemp = 0;
byte Temp2;// чтение телефона хозяина
int intUstavkaTE = 0;
int counterClearAddrDataEEprom = 0;

void setup() {
  Serial.begin(9600);  // Сериал для PC
  Serial.println("Start");
  
  gsm.begin(9600);  // Сериал для GSM
  delay(1000);
  sendATCommand("AT+CMGF=1\r", true);// устанавливает текстовый режим смс-сообщенияОК
  sendATCommand("AT+IFC=1, 1\r", true);//устанавливает программный контроль потоком передачи данных
  sendATCommand("AT+CPBS=\"SM\"\r", true);//открывает доступ к данным телефонной книги SIM-карты
  sendATCommand("AT+CNMI=1,2,2,1,0\r", true);// включает оповещение о новых сообщениях, новые сообщения 
  sendATCommand("AT+GSMBUSY=1\r\n", true);// запрет всех входящих звонков.
  sendATCommand("AT+CMGDA=DEL ALL\r\n", true);// команда удалит все сообщения
  sendATCommand("AT+CSQ", true); // Проверяем уровень сигнала

  // начинаем работу с датчиком DS по шине
    sensors.begin();
    // выполняем поиск устройств на шине
    countSensors = sensors.getDeviceCount();
//    Serial.print("Found sensors: ");
//    Serial.println(countSensors);
    // выделяем память в динамическом массиве под количество обнаруженных сенсоров
    sensorsUnique = new DeviceAddress[countSensors];

    // делаем запрос на получение адресов датчиков
    for (int i = 0; i < countSensors; i++) {
      sensors.getAddress(sensorsUnique[i], i);
    }
    // выводим полученные адреса
    for (int i = 0; i < countSensors; i++) {
      Serial.print("Device ");
      Serial.print(i);
      Serial.print(" Address: ");
      printAddress(sensorsUnique[i]);
      Serial.println();
    }

    // устанавливаем разрешение всех датчиков в 12 бит
    for (int i = 0; i < countSensors; i++) {
      sensors.setResolution(sensorsUnique[i], 12);
    }
  //Конец поиска по шине DS
}

void loop() {
  //######### Начало. Если Главного номера нет в EEPROM и запустили систему в первый раз #################
  // Удаляем из EEPROM все данные, записываем, что нет номеров и система не стоит на охране, выключаем сирену и маяк
  if (EEPROM.read(20) == 0 && counterClearAddrDataEEprom == 0){
    RAll();
  }
  //######### Конец. Если Главного номера нет в EEPROM и запустили систему в первый раз #################

  currentMillis = millis();
  
  // Запускаем GSM
  if (StartGSM == 0){
    gsm.write("AT+CMGF=1\r"); // устанавливает текстовый режим смс-сообщения
    delay(300);
  }
  if (StartGSM == 1){
    gsm.write("AT+IFC=1, 1\r"); //устанавливает программный контроль потоком передачи данных
    delay(300);
  }
  if (StartGSM == 2){
    gsm.write("AT+CPBS=\"SM\"\r");//открывает доступ к данным телефонной книги SIM-карты
    delay(300);
  }
  if (StartGSM == 3){
    gsm.write("AT+CNMI=1,2,2,1,0\r");// включает оповещение о новых сообщениях, новые сообщения 
    delay(500);
  }
  if (StartGSM == 4){
    gsm.write("AT+GSMBUSY=1\r\n"); // запрет всех входящих звонков.
    delay(300);
  }
  if (StartGSM == 5){
    gsm.write("AT+CMGDA=DEL ALL\r\n"); // команда удалит все сообщения
    delay(500);
  }
  if (FlagSignal == 0 && StartGSM == 6){
    gsm.println("AT+CSQ");// Проверяем уровень сигнала
    delay(800);
  }

  if (gsm.available()) {          //есть данные от GSM модуля
    currStr = "";                      //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
    currStrN = "";
    dataBalanceTemp = "";
    dataSms = "";
    val = "";
    flag1 = 0;
    flag2 = 0;
    while (gsm.available()) {      //сохраняем входную строку в переменную val
      c:
      ch = gsm.read();  //int
//      Serial.println(ch);
      val += char(ch);      // String
      data = ch;      // char = int
      if ('\r' == data) {
        currStr = "";
      } else if ('\n' != data) {
          currStr += String(data);
          dataSms = currStr;
        }
        //+CMT: "+79819998877","","16/04/18,20:25:08+12"
      if (data == '+' && flag1 == 0){flag1 = 1;}
      if (data == 'C' && flag1 == 1){flag1 = 2;}
      if (data == 'M' && flag1 == 2){flag1 = 3;}
      if (data == 'T' && flag1 == 3){flag1 = 4;}
      if (data == '+' && flag1 == 4){currStrN = "";flag1 = 5;}
      if (data != '"' && flag1 == 5){currStrN += String(data); dataSmsN = currStrN;}
      if (data == '"' && flag1 == 5){flag1 = 6;}
      //+CUSD: 0, "Balance:117,27r ", 15
      if (data == 'U' && flag1 == 2){flag2 = 3;}
      if (data == 'S' && flag2 == 3){flag2 = 4;}
      if (data == 'D' && flag2 == 4){flag2 = 5;}
      if (data == ':' && flag2 == 5){flag2 = 6;}
      if (data == '"' && flag2 == 6){dataBalanceTemp = ""; flag2 = 7; goto c;}
      if (data != '"' && flag2 == 7){dataBalanceTemp += String(data); dataBalance = dataBalanceTemp;}
      if (data == '"' && flag2 == 7){flag2 = 8;}
      
    }
// Смотрим данные полученные //режим кодировки СМС - обычный (для англ.)
    if (val.indexOf("+CMGF") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 1;
      }
    }
// Смотрим данные полученные //устанавливает программный контроль потоком передачи данных
    if (val.indexOf("+IFC") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 2;
      }
    }
// Смотрим данные полученные //открывает доступ к данным телефонной книги SIM-карты
    if (val.indexOf("+CPBS") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 3;
      }
    }
// Смотрим данные полученные //включает оповещение о новых сообщениях, новые сообщения
    if (val.indexOf("+CNMI") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 4;
      }
    }
// Смотрим данные полученные //запрет всех входящих звонков.
    if (val.indexOf("+GSMBUSY") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 5;
      }
    }
// Смотрим данные полученные //команда удалит все сообщения
    if (val.indexOf("+CMGDA") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 6;
      }
    }
// Смотрим данные полученные от модуля +CSQ: 22,0
    if (val.indexOf("+CSQ") > -1) {
      for (i=0; i<=20; i++){
        if (val[i] == 58) {
          intNumberLevelFirst = val[i+2]-48;
          if (val[i+3] == 44){ intNumberLevelSecond = 0;}
          if (val[i+3] != 44){ intNumberLevelSecond = val[i+3]-48;}
          if (val[i+3] == 44){IntSignalLevel = intNumberLevelFirst;}
          if (val[i+3] != 44){IntSignalLevel = (intNumberLevelFirst*10) + intNumberLevelSecond;}
        }
        
      }
      if (IntSignalLevel == 99 || IntSignalLevel == 0){
        FlagSignal = 0; StartGSM = 0;
//        digitalWrite(ledRed, HIGH);
      }
      if (IntSignalLevel <=32 && IntSignalLevel !=0){
        FlagSignal = 1;
      }
    }
    
// Смотрим данные полученные от модуля пришло смс
    if (val.indexOf("+CMTI:") > -1) { // +CMTI: "SM",
      StartGSM = 0;
    }
    
// Смотрим данные полученные от модуля, Получили смс с балансом, теперь отсылаем
    if (val.indexOf("+CUSD:") > -1) {       // Пришло уведомление о USSD-ответе
      if (val.indexOf("\"") > -1) {       // Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
        msgBalance = val.substring(val.indexOf("\"") + 2);  // Получаем непосредственно текст
        msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
        balance = getFloatFromString(msgBalance);       // Извлекаем информацию о балансе
        
        if (tempBalans == 1) {
          Boss = BossTemp;
          textToSend = BalansSim;
          textToSend += (String)balance;
          textToSend += "руб";
          smsSendAlarm(textToSend);
          tempBalans = 0;
          BossTemp = 0;
        }
        
        if ((int)balance > 400){
          tempForWaitSendSmsTE = 0;
          // ничего не делаем
        }else if (tempZaprosBalansa == 1){
          if ((int)balance == 0){
            tempZaprosBalansa = 2;
            GoBalans();
          }else {
            Boss = 75;
            textToSend = BalansSim;
            textToSend += "меньше 400руб, ваш баланс: ";
            textToSend += (String)balance;
            smsSendAlarm(textToSend);
            tempZaprosBalansa = 0;
            tempForWaitSendSmsTE = 1;
          }
          
        }
      
      }
    }

//----------------------- определение факта приема СМС и сравнение номера(ов) с заданным(и)
    if (val.indexOf("+CMT") > -1) {
      
// Регистрация хозяина
      if (dataSms.indexOf("Register") > -1 && EEPROM.read(0) == 3) {
        if (EEPROM.read(20) == 0){
          k=1;
          Temp = "";
          for (i=20; i<=30; i++){            // записываем с 20 по 30 ячейку номер телефона главного
            EEPROM.write(i,dataSmsN[k]-48);
            Temp += dataSmsN[k]-48; // записываем в Temp номер телефона из прешедшей смс
            k++;
          }
          EEPROM.write(0,0);
          textToSend = "";
          Serial1.print("Register"); Serial1.print(Temp);Serial1.println();
          Boss = 1;
          textToSend = HelloNumberIsBoss;
          textToSend += Temp;
          smsSendAlarm(textToSend);
          goto Exit;
        }
        Exit:
        ClearDataIn();
        delay(1);
        
      }

      
// Проверяем номер телефона хозяина
      if (dataSmsN !=""){
        Boss = 0;
        for (i=1; i<=11; i++){
          Temp += dataSmsN[i]-48; // записываем в Temp номер телефона из прешедшей смс
        }
        ReadNumber(1);// читаем номер хозяина из EEPROM
        
        if (Temp == NBoss){// Сравниваем номер прешедшей смс с номером из памяти
          Boss = 1;
          NBoss = "";
          goto exitWriteNumber;
        }
        ReadNumber(2);// читаем номер хозяина из EEPROM
        if (Temp == NBoss1){// Сравниваем номер прешедшей смс с номером из памяти
          Boss = 2;
          NBoss1 = "";
          goto exitWriteNumber;
        }
        ReadNumber(3);// читаем номер хозяина из EEPROM
        if (Temp == NBoss2){// Сравниваем номер прешедшей смс с номером из памяти
          Boss = 3;
          NBoss2 = "";
          goto exitWriteNumber;
        }
        ReadNumber(4);// читаем номер хозяина из EEPROM
        if (Temp == NBoss3){// Сравниваем номер прешедшей смс с номером из памяти
          Boss = 4;
          NBoss3 = "";
          goto exitWriteNumber;
        }
        ReadNumber(5);// читаем номер хозяина из EEPROM
        if (Temp == NBoss4){// Сравниваем номер прешедшей смс с номером из памяти
          Boss = 5;
          NBoss4 = "";
          goto exitWriteNumber;
        }
        ReadNumber(6);// читаем номер хозяина из EEPROM
        if (Temp == NBoss5){// Сравниваем номер прешедшей смс с номером из памяти
          Boss = 6;
          NBoss5 = "";
          goto exitWriteNumber;
        }
        exitWriteNumber:
        delay(1);
      }

// Помощь, вывод меню в смс
        if (dataSms.indexOf("Help") > -1){
          if (Boss == 1 || Boss == 2 || Boss == 3 || Boss == 4 || Boss == 5 || Boss == 6){
            temp = "Hi";//25
            temp += "\r\n";//29
            temp += "Balans";
            smsSendAlarm(temp);
            temp = "";                   // очищаем переменную
          }
        }
// Информация
        if (dataSms.indexOf("Info") > -1){
          if (Boss == 1 || Boss == 2 || Boss == 3 || Boss == 4 || Boss == 5 || Boss == 6){
            
            Boss = 77;
            textToSend = "Инфа";
            textToSend += "\r\n";
            textToSend += "Сигнал:";
            IntSignalLevelTemp = map(IntSignalLevel, 0, 32, 0, 100);
            textToSend += String(IntSignalLevelTemp);
            textToSend += "%";
            textToSend += "\r\n";
            textToSend += "Темп:";
            textToSend += STemperature1;
            textToSend += "'С";
            smsSendAlarm(textToSend);textToSend = "";
          }
        }
// Запрос баланса, после получения ответа - отправка обратно на номер
        if (dataSms.indexOf("Balans") > -1) {    // Запрос баланса
          if (Boss == 1 || Boss == 2 || Boss == 3 || Boss == 6){
            BossTemp = Boss;
            tempBalans = 1;
            GoBalans();
          }
        }

        
    }//+cmt
    ClearDataIn();
    
  }

  //Начало чтения для датчиков по шине 1-Wire
  if (currentMillis - lastUpdateTime1WIRE > TEMP_UPDATE_TIME1WIRE)
  {
//    goto ENDWire;
    lastUpdateTime1WIRE = currentMillis;
    if (countSensors >= 1) {
      // переменная для хранения температуры
      float temperature[10];
      // отправляем запрос на измерение температуры всех сенсоров
      sensors.requestTemperatures();
      // считываем данные из регистра каждого датчика по очереди
      for (i = 0; i < countSensors; i++) {
        temperature[i] = sensors.getTempCByIndex(i);
        if (i == 0) {
                      Serial.print("TE 1: ");
                      Serial.println(temperature[0]);
                      STemperature1 = temperature[0];
        }
//        if (i == 1) {
//                      Serial.print("TE 2: ");
//                      Serial.println(temperature[1]);
//                      STemperature2 = temperature[1];
//        }
//        if (i == 2) {
//                      Serial.print("TE 3: ");
//                      Serial.println(temperature[2]);
//                      STemperature3 = temperature[2];
//        }
      }
    }
  }//Конец для датчиков 1-Wire
}

String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                            // Переменная для хранения результата
//  Serial.print("CMD: ");                          // Дублируем команду в монитор порта
//  Serial.println(cmd);                          // Дублируем команду в монитор порта
  gsm.println(cmd);                          // Отправляем команду модулю
  if (waiting) {                                // Если необходимо дождаться ответа...
    _resp = waitResponse();                     // ... ждем, когда будет передан ответ
    // Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
    if (_resp.startsWith(cmd)) {  // Убираем из ответа дублирующуюся команду
      _resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
    }
//    Serial.println(_resp);                      // Дублируем ответ в монитор порта
  }
  return _resp;                                 // Возвращаем результат. Пусто, если проблема
}

// Функция ожидания ответа и возврата полученного результата
String waitResponse() {                         // Функция ожидания ответа и возврата полученного результата
  String _resp = "";                            // Переменная для хранения результата
  long _timeout = millis() + 10000;             // Переменная для отслеживания таймаута (10 секунд)
  while (!gsm.available() && millis() < _timeout)  {}; // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (gsm.available()) {                     // Если есть, что считывать...
    _resp = gsm.readString();                // ... считываем и запоминаем
  }
  else {                                        // Если пришел таймаут, то...
//    Serial.println("Timeout...");               // ... оповещаем об этом и...
  }
  return _resp;                                 // ... возвращаем результат. Пусто, если проблема
}

// Обработка смс цифр из сообщения - для парсинга баланса из USSD-запроса
float getFloatFromString(String str) {            // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
  bool flag = false;
  String result = "";
  str.replace(",", ".");                          // Если в качестве разделителя десятичных используется запятая - меняем её на точку.
  for (int i = 0; i < str.length(); i++) {
    if (isDigit(str[i]) || (str[i] == (char)46 && flag)) {        // Если начинается группа цифр (при этом, на точку без цифр не обращаем внимания),
      if (result == "" && i > 0 && (String)str[i - 1] == "-") {   // Нельзя забывать, что баланс может быть отрицательным
        result += "-";                            // Добавляем знак в начале
      }
      result += str[i];                           // начинаем собирать их вместе
      if (!flag) flag = true;                     // Выставляем флаг, который указывает на то, что сборка числа началась.
    }
    else  {                                       // Если цифры закончились и флаг говорит о том, что сборка уже была,
      if (str[i] != (char)32) {                   // Если порядок числа отделен пробелом - игнорируем его, иначе...
        if (flag) break;                          // ...считаем, что все.
      }
    }
  }
  return result.toFloat();                        // Возвращаем полученное число.
}


//процедура отправки СМС
void smsSendAlarm(String text) {
  textToSend = "";
  //Главный номер
  if (EEPROM.read(20) == 7 && Boss == 1 || EEPROM.read(20) == 7 && Boss == 75 || EEPROM.read(20) == 7 && Boss == 74 || EEPROM.read(20) == 7 && Boss == 77 || EEPROM.read(20) == 7 && Boss == 80 || EEPROM.read(20) == 7 && Boss == 82 || EEPROM.read(20) == 7 && Boss == 83){
    ReadNumber(1);
    sendSms(text, NBoss);
  }
  //User1 31-41,
  if (EEPROM.read(31) == 7 && Boss == 2 || EEPROM.read(31) == 7 && Boss == 75 || EEPROM.read(31) == 7 && Boss == 83 || EEPROM.read(31) == 7 && Boss == 74){
    ReadNumber(2);
    sendSms(text, NBoss1);
  }
  //User2 42-52,
  if (EEPROM.read(42) == 7 && Boss == 3 || EEPROM.read(42) == 7 && Boss == 75 || EEPROM.read(42) == 7 && Boss == 83 || EEPROM.read(42) == 7 && Boss == 74){
    ReadNumber(3);
    sendSms(text, NBoss2);
  }
  //User3 53-63 
  if (EEPROM.read(53) == 7 && Boss == 4 || EEPROM.read(53) == 7 && Boss == 82 || EEPROM.read(53) == 7 && Boss == 83){
    ReadNumber(4);
    sendSms(text, NBoss3);
  }
  //User4 64-74 
  if (EEPROM.read(64) == 7 && Boss == 5 || EEPROM.read(64) == 7 && Boss == 82 || EEPROM.read(64) == 7 && Boss == 83){
    ReadNumber(5);
    sendSms(text, NBoss4);
  }
  //User5 75-85 
  if (EEPROM.read(75) == 7 && Boss == 6 || EEPROM.read(75) == 7 && Boss == 75  || EEPROM.read(75) == 7 && Boss == 77 || EEPROM.read(75) == 7 && Boss == 80 || EEPROM.read(75) == 7 && Boss == 82 || EEPROM.read(75) == 7 && Boss == 83){
    ReadNumber(6);
    sendSms(text, NBoss5);
  }
  text = "";
  NBoss = "";
  NBoss1 = "";
  NBoss2 = "";
  NBoss3 = "";
  NBoss4 = "";
  NBoss5 = "";
  sendATCommand("AT+CMGDA=DEL ALL\r\n", true);
  sendATCommand("AT+CMGD=4", true);
  sendATCommand("AT+CMGF=1", true); // устанавливает текстовый режим смс-сообщения
  Boss = 0;
}

//Отправка смс о балансе
void GoBalans(){
  sendATCommand("AT+CUSD=1,\"#100#\"", true);
}

//Начинаем поиск номера
void ReadNumber(int numberN){
  if (numberN == 1){
    NBoss = "";
    SearchN(20, 30);
    NBoss = NBoss;
    return NBoss;
  }
  if (numberN == 2){
    NBoss = "";
    SearchN(31, 41);
    NBoss1 = NBoss;
    NBoss = "";
    return NBoss1;
  }
  if (numberN == 3){
    NBoss = "";
    SearchN(42, 52);
    NBoss2 = NBoss;
    NBoss = "";
    return NBoss2;
  }
  if (numberN == 4){
    NBoss = "";
    SearchN(53, 63);
    NBoss3 = NBoss;
    NBoss = "";
    return NBoss3;
  }
  if (numberN == 5){
    NBoss = "";
    SearchN(64, 74);
    NBoss4 = NBoss;
    NBoss = "";
    return NBoss4;
  }
  if (numberN == 6){
    NBoss = "";
    SearchN(75, 85);
    NBoss5 = NBoss;
    NBoss = "";
    return NBoss5;
  }
}

//ищем номер в EEPROM
void SearchN(int firstI, int secondI){
  for (i=firstI;i<=secondI;i++){
    Temp2 = EEPROM.read(i);
    if (Temp2 == 0){NBoss += "0";}
    if (Temp2 == 1){NBoss += "1";}
    if (Temp2 == 2){NBoss += "2";}
    if (Temp2 == 3){NBoss += "3";}
    if (Temp2 == 4){NBoss += "4";}
    if (Temp2 == 5){NBoss += "5";}
    if (Temp2 == 6){NBoss += "6";}
    if (Temp2 == 7){NBoss += "7";}
    if (Temp2 == 8){NBoss += "8";}
    if (Temp2 == 9){NBoss += "9";}
  }
  return NBoss;
  Temp2 = 0;
}

// Удаление всех настроек и номера из памяти EEPROM
void RAll(){
  ClearAddresDataEEPROM();
  WriteEEPROM(); // Записываем значения по умолчанию
  Info(); // Вывод в Serial Инфу
  counterClearAddrDataEEprom = 1;
  
}

// Очистка EEPROM
void ClearAddresDataEEPROM(){ 
  for (i=0; i<=100; i++){
    EEPROM.write(i,0);
  }
}

void WriteEEPROM(){
  //0=48-48
  //1=49-48
  //2=50-48
  //3=51-48
  //4=52-48
  //5=53-48
  //6=54-48
  //7=55-48
  //8=56-48
  //9=57-48
  EEPROM.write(0,3);   //состоянии системы = 3(в режиме регистации)
//  EEPROM.write(75,3);//Уставка температуры, первая цифра
//  EEPROM.write(76,0);//Уставка температуры, вторая цифра
//  intUstavkaTE = EEPROM.read(75) * 10;
//  intUstavkaTE = intUstavkaTE + EEPROM.read(76);
}

void Info(){
    Serial.println("Info");
    delay(1);
    // Состояние регистрации системы
    Serial.print("State system register or not: ");
    Serial.println(EEPROM.read(0));
    
//   20-30 - Храним номер №1 Хозяина
    Serial.print("Number phone 1: ");
    for (i=20; i<=30; i++){
      Serial.print(EEPROM.read(i));
    }
    Serial.println("");
  
  // 31-41 - Храним номер №2
    Serial.print("Number phone 2: ");
    for (i=31; i<=41; i++){
      Serial.print(EEPROM.read(i));
    }
    Serial.println("");
    
  // 42-52 - Храним номер №3
    Serial.print("Number phone 3: ");
    for (i=42; i<=52; i++){
      Serial.print(EEPROM.read(i));
    }
    Serial.println("");
    
  // 53-63 - Храним номер №4
    Serial.print("Number phone 4: ");
    for (i=53; i<=63; i++){
      Serial.print(EEPROM.read(i));
    }
    Serial.println("");
    
  // 64-74 - Храним номер №5
    Serial.print("Number phone 5: ");
    for (i=64; i<=74; i++){
      Serial.print(EEPROM.read(i));
    }
    Serial.println("");
    
  // 75-85 - Храним номер №6
    Serial.print("Number phone 6: ");
    for (i=75; i<=85; i++){
      Serial.print(EEPROM.read(i));
    }
    Serial.println("");
}

// Очистка временных переменных
void ClearDataIn(){
  Temp = "";
//  Boss = 0;
  currStr = "";
  currStrN = "";
  dataBalanceTemp = "";
  dataSms = "";
  dataSmsN = "";
//  dataBalance = "";
  val = "";
  flag1 = 0;
  flag2 = 0;
}

// Отправка смс
void sendSms(String textForSend, String Number){
  sendSMSinPDU(Number, textForSend);
  do {
    _response = sendATCommand("AT+CLIP=1", true);  // Включаем АОН
    _response.trim();                       // Убираем пробельные символы в начале и конце
  } while (_response != "OK");              // Не пускать дальше, пока модем не вернет ОК
  
  
}

void sendSMSinPDU(String phone, String message)
{
//  Serial.println("Отправляем сообщение: " + message);

  // ============ Подготовка PDU-пакета =============================================================================================
  // В целях экономии памяти будем использовать указатели и ссылки
  String *ptrphone = &phone;                                    // Указатель на переменную с телефонным номером
  String *ptrmessage = &message;                                // Указатель на переменную с сообщением

  String PDUPack;                                               // Переменная для хранения PDU-пакета
  String *ptrPDUPack = &PDUPack;                                // Создаем указатель на переменную с PDU-пакетом

  int PDUlen = 0;                                               // Переменная для хранения длины PDU-пакета без SCA
  int *ptrPDUlen = &PDUlen;                                     // Указатель на переменную для хранения длины PDU-пакета без SCA

  getPDUPack(ptrphone, ptrmessage, ptrPDUPack, ptrPDUlen);      // Функция формирующая PDU-пакет, и вычисляющая длину пакета без SCA

//  Serial.println("PDU-pack: " + PDUPack);
//  Serial.println("PDU length without SCA:" + (String)PDUlen);

  // ============ Отправка PDU-сообщения ============================================================================================
  sendATCommand("AT+CMGF=0", true);                             // Включаем PDU-режим
  sendATCommand("AT+CMGS=" + (String)PDUlen, true);             // Отправляем длину PDU-пакета
  sendATCommand(PDUPack + (String)((char)26), true);            // После PDU-пакета отправляем Ctrl+Z
  PDUPack = "";
  message = "";
  *ptrphone = "";
  *ptrmessage = "";
  *ptrPDUlen = "";
}

void getPDUPack(String *phone, String *message, String *result, int *PDUlen)
{
  // Поле SCA добавим в самом конце, после расчета длины PDU-пакета
  *result += "01";                                // Поле PDU-type - байт 00000001b
  *result += "00";                                // Поле MR (Message Reference)
  *result += getDAfield(phone, true);             // Поле DA
  *result += "00";                                // Поле PID (Protocol Identifier)
  *result += "08";                                // Поле DCS (Data Coding Scheme)
  //*result += "";                                // Поле VP (Validity Period) - не используется

  String msg = StringToUCS2(*message);            // Конвертируем строку в UCS2-формат

  *result += byteToHexString(msg.length() / 2);   // Поле UDL (User Data Length). Делим на 2, так как в UCS2-строке каждый закодированный символ представлен 2 байтами.
  *result += msg;

  *PDUlen = (*result).length() / 2;               // Получаем длину PDU-пакета без поля SCA
  *result = "00" + *result;                       // Добавляем поле SCA
}

String getDAfield(String *phone, bool fullnum) {
  String result = "";
  for (int i = 0; i <= (*phone).length(); i++) {  // Оставляем только цифры
    if (isDigit((*phone)[i])) {
      result += (*phone)[i];
    }
  }
  int phonelen = result.length();                 // Количество цифр в телефоне
  if (phonelen % 2 != 0) result += "F";           // Если количество цифр нечетное, добавляем F

  for (int i = 0; i < result.length(); i += 2) {  // Попарно переставляем символы в номере
    char symbol = result[i + 1];
    result = result.substring(0, i + 1) + result.substring(i + 2);
    result = result.substring(0, i) + (String)symbol + result.substring(i);
  }

  result = fullnum ? "91" + result : "81" + result; // Добавляем формат номера получателя, поле PR
  result = byteToHexString(phonelen) + result;    // Добавляем длину номера, поле PL

  return result;
}

// =================================== Блок кодирования строки в представление UCS2 =================================
String StringToUCS2(String s)
{
  String output = "";                                               // Переменная для хранения результата

  for (int k = 0; k < s.length(); k++) {                            // Начинаем перебирать все байты во входной строке
    byte actualChar = (byte)s[k];                                   // Получаем первый байт
    unsigned int charSize = getCharSize(actualChar);                // Получаем длину символа - кличество байт.

    // Максимальная длина символа в UTF-8 - 6 байт плюс завершающий ноль, итого 7
    char symbolBytes[charSize + 1];                                 // Объявляем массив в соответствии с полученным размером
    for (int i = 0; i < charSize; i++)  symbolBytes[i] = s[k + i];  // Записываем в массив все байты, которыми кодируется символ
    symbolBytes[charSize] = '\0';                                   // Добавляем завершающий 0

    unsigned int charCode = symbolToUInt(symbolBytes);              // Получаем DEC-представление символа из набора байтов
    if (charCode > 0)  {                                            // Если все корректно преобразовываем его в HEX-строку
      // Остается каждый из 2 байт перевести в HEX формат, преобразовать в строку и собрать в кучу
      output += byteToHexString((charCode & 0xFF00) >> 8) +
                byteToHexString(charCode & 0xFF);
    }
    k += charSize - 1;                                              // Передвигаем указатель на начало нового символа
    if (output.length() >= 280) break;                              // Строка превышает 70 (4 знака на символ * 70 = 280) символов, выходим
  }
  return output;                                                    // Возвращаем результат
}

String byteToHexString(byte i) { // Функция преобразования числового значения байта в шестнадцатиричное (HEX)
  String hex = String(i, HEX);
  if (hex.length() == 1) hex = "0" + hex;
  hex.toUpperCase();
  return hex;
}

unsigned int getCharSize(unsigned char b) { // Функция получения количества байт, которыми кодируется символ
  // По правилам кодирования UTF-8, по старшим битам первого октета вычисляется общий размер символа
  // 1  0xxxxxxx - старший бит ноль (ASCII код совпадает с UTF-8) - символ из системы ASCII, кодируется одним байтом
  // 2  110xxxxx - два старших бита единицы - символ кодируется двумя байтами
  // 3  1110xxxx - 3 байта и т.д.
  // 4  11110xxx
  // 5  111110xx
  // 6  1111110x

  if (b < 128) return 1;             // Если первый байт из системы ASCII, то он кодируется одним байтом

  // Дальше нужно посчитать сколько единиц в старших битах до первого нуля - таково будет количество байтов на символ.
  // При помощи маски, поочереди исключаем старшие биты, до тех пор пока не дойдет до нуля.
  for (int i = 1; i <= 7; i++) {
    if (((b << i) & 0xFF) >> 7 == 0) {
      return i;
    }
  }
  return 1;
}

unsigned int symbolToUInt(const String& bytes) {  // Функция для получения DEC-представления символа
  unsigned int charSize = bytes.length();         // Количество байт, которыми закодирован символ
  unsigned int result = 0;
  if (charSize == 1) {
    return bytes[0]; // Если символ кодируется одним байтом, сразу отправляем его
  }
  else  {
    unsigned char actualByte = bytes[0];
    // У первого байта оставляем только значимую часть 1110XXXX - убираем в начале 1110, оставляем XXXX
    // Количество единиц в начале совпадает с количеством байт, которыми кодируется символ - убираем их
    // Например (для размера 2 байта), берем маску 0xFF (11111111) - сдвигаем её (>>) на количество ненужных бит (3 - 110) - 00011111
    result = actualByte & (0xFF >> (charSize + 1)); // Было 11010001, далее 11010001&(11111111>>(2+1))=10001
    // Каждый следующий байт начинается с 10XXXXXX - нам нужны только по 6 бит с каждого последующего байта
    // А поскольку остался только 1 байт, резервируем под него место:
    result = result << (6 * (charSize - 1)); // Было 10001, далее 10001<<(6*(2-1))=10001000000

    // Теперь у каждого следующего бита, убираем ненужные биты 10XXXXXX, а оставшиеся добавляем к result в соответствии с расположением
    for (int i = 1; i < charSize; i++) {
      actualByte = bytes[i];
      if ((actualByte >> 6) != 2) return 0; // Если байт не начинается с 10, значит ошибка - выходим
      // В продолжение примера, берется существенная часть следующего байта
      // Например, у 10011111 убираем маской 10 (биты в начале), остается - 11111
      // Теперь сдвигаем их на 2-1-1=0 сдвигать не нужно, просто добавляем на свое место
      result |= ((actualByte & 0x3F) << (6 * (charSize - 1 - i)));
      // Было result=10001000000, actualByte=10011111. Маской actualByte & 0x3F (10011111&111111=11111), сдвигать не нужно
      // Теперь "пристыковываем" к result: result|11111 (10001000000|11111=10001011111)
    }
    return result;
  }
}

// функция вывода адреса датчика
void printAddress(DeviceAddress deviceAddress){
  for (uint8_t i = 0; i < 8; i++){
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

 

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Приветствую.
А схему устройства увидеть можно?

b707
Offline
Зарегистрирован: 26.05.2017

Пипец, 900 строк чтоб отправить температуру по Смс?

b707
Offline
Зарегистрирован: 26.05.2017

Строка 618 и далее - это еще повезло, что цифр в арифметике всего 10. Страшно представить, сколько понадобилось бы условий, чтобы отыскать в тексте каждую букву кириллицы и латиницы обоих регистров.
Стамбулов, вы про массивы и циклы не слыхали?

Павел74
Offline
Зарегистрирован: 27.03.2019

ГРАНДИОЗНО!!!!!!!!! Я только в руки взял SIM800L  - пробую разобраться, ранее так же с нуля освоил NRF24 (делал на нем радиоуправление строительного крана - самоделка в помощь на моей стройке) 

По SIM800L  - пока тренируюсь с терминала, чтоб в дальнейшем проект отработат в Atmel Studio 7

 

возник вопрос по передаче смс - в начале настройка:

AT+CMGF=1\r\n - установка текстового режима.
AT+CSMP=17,167,0,0\r\n - установка параметров текстового режима.
AT+CMGS="+7XXXXXXXXXX"\r\n - номер получателя SMS.
>\r\n - ответ модуля (модуль готов принять текст SMS). -----------А ВОТ ТУТ Я ЗАВИС - отправляю текст ( латиница) - результат - ноль, 
к примеру нужно послать "HELLO" - как это должно выглядель ? почти все варианты уже испробовал - не могу верно понять рекомендацию :
 
 {     TEXT - ввод и отправка текста в модуль. Как только в тексте встретится символ <0x1A>, сообщение будет отправлено. Если в тексте встретится символ <0x1B>, сообщение не будет отправлено.
Примечание:
- В текстовом режиме можно добавлять в текст SMS сообщения символы переноса строки \r\n., в т.ч. перед символом подтверждающим/запрещающим отправку SMS.}  - это 

 

Павел74
Offline
Зарегистрирован: 27.03.2019

/

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Если Вы впервые держите в руках  SIM800L - то советую сюда - http://codius.ru/articles?page=1

 

andyparker
Offline
Зарегистрирован: 20.12.2020
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 12


SoftwareSerial SIM800(8, 9);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);


const String MAIN_PHONE = "+71234567890";                              // Основной номер
const String WHITE_LIST = "+71234567890; +79999999999; +79888888888";  // Включить основной и дополнительный/е телефоны в белый список
const String TEXT_USSD_BALANCE_QUERY = "AT+CUSD=1,\"*100#\"";          // Отправляет ТЕКСТОВЫЙ ответ, а не PDU-пакет, альтернативный запрос - "#100#"
const String BALANCE_TEXT_QUERY = "Balance";                           // Содержание СМС для получения текстового ответа на запрос о балансе
const String TEMPERATURE_QUERY = "Temperature";                        // Содержание СМС для получения ответа на запрос о температуре
const String CURRENCY = " BYN";                                        // Текстовое представление валюты
const float  BALANCE_TRESHOLD = 15.0;                                  // Нижнее пороговое значение температуры
const float  TEMPERATURE_TRESHOLD = 24.0;                              // Нижнее пороговое значение баланса


String sendATCommand(const String& cmd, bool waiting) {
  String response = "";
  Serial.println(cmd);
  SIM800.println(cmd);
  if (waiting) {
    response = waitAndReturnResponse();
    if (response.startsWith(cmd)) {
      response = response.substring(response.indexOf("\r", cmd.length()) + 2);
    }
    Serial.println(response);
  }
  return response;
}

String waitAndReturnResponse() {
  String response = "";
  int64_t timeout = millis() + 10000;
  while (!SIM800.available() && millis() < timeout) {};
  if (SIM800.available()) {
    response = SIM800.readString();
  }
  else {
    Serial.println("Timeout...");
  }
  return response;
}

void sendSMS(const String& phone, const String& message) {
  sendATCommand("AT+CMGS=\"" + phone + "\"", true);
  sendATCommand(message + (String)((char)26), true);
}

void checkBalance(const String& number) {
  sendATCommand(TEXT_USSD_BALANCE_QUERY, true);
  String answer = waitAndReturnResponse();
  answer.trim();
  Serial.println("\r\nBalans SIM karty: " + (String)extractBalanceFromString(answer));
  sendSMS(number, "\r\nBalans SIM karty: " + (String)extractBalanceFromString(answer) + CURRENCY + ".");
}

float getFloatFromString(String str) {                                      // Функция извлечения цифр из сообщения - для парсинга баланса из USSD-запроса
  bool flag = false;
  String result = "";
  str.replace(",", ".");                                                    // Если в качестве разделителя десятичных используется запятая - меняем её на точку.
  for (size_t i = 0; i < str.length(); ++i) {
    if (isDigit(str[i]) || (str[i] == (char)46 && flag)) {                  // Если начинается группа цифр (при этом на точку без цифр не обращаем внимания),
      if (i != 0 && result == "" && (String)str[i - 1] == "-") {            // Нельзя забывать, что баланс может быть отрицательным
        result += "-";                                                      // Добавляем знак в начале
      }
      result += str[i];                                                     // Начинаем собирать их вместе
      if (!flag) {
        flag = true;                                                        // Выставляем флаг, который указывает на то, что сборка числа началась.
      }
    }
    else if (str[i] != (char)32 && flag) {
      break;
    }
  }
  return result.toFloat();                                                  // Возвращаем полученное число
}

void parseSMS(String msg) {                                   // Парсим SMS
  String msgheader  = "";                                     // Переменная под звонивший телефона для анализа
  String msgbody    = "";                                     // Переменная под SMS
  String msgphone   = "";                                     // Переменная под номер телефона

  msg = msg.substring(msg.indexOf("+CMGR: "));
  msgheader = msg.substring(0, msg.indexOf("\r"));            // Получаем звонивший телефон

  msgbody = msg.substring(msgheader.length() + 2);
  msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK"));  // Получаем текст полученной SMS
  msgbody.trim();                                             // Обрезаем начальные или концевые символы

  int firstIndex = msgheader.indexOf("\",\"") + 3;
  int secondIndex = msgheader.indexOf("\",\"", firstIndex);
  msgphone = msgheader.substring(firstIndex, secondIndex);
  if (WHITE_LIST.indexOf(msgphone) != -1) {                   // Если телефон в белом списке, то...
    if (msgbody == BALANCE_TEXT_QUERY) {
      checkBalance(msgphone);
    }
    else if (msgbody == TEMPERATURE_QUERY) {
      sendSMS(msgphone, "Sensor temperature: " +
              String(obtainTemperature()) + " C.");
    }
    Serial.println("Phone: " + msgphone);                      // Выводим номер телефона
    Serial.println("Message: " + msgbody);                     // Выводим текст SMS
  }
  else if (msgphone.length()) {
    Serial.println("Unknown phone number: " + msgphone);
    Serial.println("Message: " + msgbody);
  }
}

void checkNewMessages() {
  static bool hasmsg = false;
  String response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);                     // Отправляем запрос чтения непрочитанных сообщений
  if (response.indexOf("+CMGL: ") >= 0) {                                                // Если есть хоть одно, получаем его индекс
    int msgIndex = response.substring(response.indexOf("+CMGL: ") + 7,
                                      response.indexOf("\"REC UNREAD\"",
                                          response.indexOf("+CMGL: ")) - 1).toInt();
    response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true);                // Пробуем получить текст SMS по индексу
    response.trim();                                                                     // Убираем пробелы в начале/конце
    if (response.endsWith("OK")) {                                                       // Если ответ заканчивается на "ОК"
      if (!hasmsg) {
        hasmsg = true;                                                                   // Ставим флаг наличия сообщений для удаления
      }
      sendATCommand("AT+CMGR=" + (String)msgIndex, true);                                // Делаем сообщение прочитанным
      sendATCommand("\n", true);                                                         // Перестраховка - вывод новой строки
      parseSMS(response);                                                                // Отправляем текст сообщения на обработку
    }
  }
  else {
    if (hasmsg == true) {
      sendATCommand("AT+CMGDA=\"DEL READ\"", true);                                      // Удаляем все прочитанные сообщения
      hasmsg = false;
    }
  }
}

void modemQueryAndResponse() {
  if (SIM800.available())   {                                                             // Если модем что-то получил...
    String data = waitAndReturnResponse();                                                // Получаем ответ для модема для анализа
    data.trim();                                                                          // Убираем лишние пробелы в начале и конце
    parseSMS(data);
    Serial.println(data);                                                                 // Если нужно, выводим в монитор порта
    if (data.startsWith("+CUSD:")) {                                                      // Пришло уведомление об USSD-ответе
      if (data.indexOf("\"") > -1) {                                                      // Если ответ содержит кавычки, значит есть сообщение (предохранитель от "пустых" USSD-ответов)
        float balance = extractBalanceFromString(data);
        Serial.println("\r\nBalans SIM karty: " + (String)balance + CURRENCY + ".");
      }
    }
  }
  else if (Serial.available())  {                                                         // Ожидаем команды по Serial...
    SIM800.write(Serial.read());                                                          // ... и отправляем полученную команду модему
  }
}

float obtainTemperature() {
  sensors.requestTemperatures();
  return sensors.getTempCByIndex(0);
}

void tresholdTemperature(float current_temperature) {
  static bool flag = 1;
  if (current_temperature < TEMPERATURE_TRESHOLD && flag) {
    sendSMS(MAIN_PHONE, "Temperature is currently below " + String(TEMPERATURE_TRESHOLD) +
            " C and equal to " + String(current_temperature) + " C.");
    flag = 0;
  }
  else if (current_temperature >= TEMPERATURE_TRESHOLD && !flag) {
    flag = 1;
  }
}

float extractBalanceFromString(const String& response) {
  String msgBalance = response.substring(response.indexOf("\"") + 2);
  msgBalance = msgBalance.substring(0, msgBalance.indexOf("\""));
  return getFloatFromString(msgBalance);
}

void balanceChecking() {
  static bool flag = 1;
  sendATCommand(TEXT_USSD_BALANCE_QUERY, true);
  String answer = waitAndReturnResponse();
  answer.trim();
  float balance = extractBalanceFromString(answer);
  Serial.println("Balance is " + String(balance));
  if (balance < BALANCE_TRESHOLD && flag) {
    sendSMS(MAIN_PHONE, "Balance is below " + String(BALANCE_TRESHOLD) +
            CURRENCY + " and equal to " + String(balance) + CURRENCY + ".");
    flag = 0;
  }
  else if (balance >= BALANCE_TRESHOLD && !flag) {
    flag = 1;
  }
}

void setup() {
  Serial.begin(9600);
  SIM800.begin(9600);

  sensors.begin();
  sensors.requestTemperatures();

  Serial.println("Start!");

  sendATCommand("AT", true);
  sendATCommand("AT+CMGDA=\"DEL ALL\"", true);
  sendATCommand("AT+CLIP=1", true);
  sendATCommand("AT+CMGF=1;&W", true);
}

void loop() {
  static int64_t balance_check_timer = 0;
  static int64_t temperature_check_timer = 0;
  static int64_t new_message_check_timer = 0;

  modemQueryAndResponse();
  if (abs(millis() - new_message_check_timer) >= 5000) {
    checkNewMessages();
    new_message_check_timer = millis();
  }
  if (abs(millis() - temperature_check_timer) >= 10000) {
    tresholdTemperature(obtainTemperature());
    temperature_check_timer = millis();
  }
  if (abs(millis() - balance_check_timer) >= 300000) {
    balanceChecking();
    balance_check_timer = millis();
  }
}

Вот версия скетча для температурного датчика, отправляет СМС при снижении баланса, температуры ниже определенного уровня, также можно по запросу получить эти параметры в ответном СМС.

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

andyparker с каких пор вы постите чужое?

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Приношу свои извинения andyparker!
Это и его код тоже.
Он вложил в него очень большой труд.
Его полезные советы помогли оживить устройство.
Теперь оно стабильно работает!!!

b707
Offline
Зарегистрирован: 26.05.2017

wiksoft.arduino пишет:

andyparker с каких пор вы постите чужое?

wiksoft.arduino пишет:

Приношу свои извинения andyparker!

что это было?

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

В понедельник узнаем)))

wiksoft.arduino
Offline
Зарегистрирован: 18.01.2021

Уже разобрались.
Все в порядке!