Код для простейшей схемы

Добрый день .
Помогите пож-та новичку собрать программный код в Ардуино Нано .В программировании я пока зеленый но собрать схему очень нужно.
Сценарий контроль модуля такой : По Смс/звонку открыть контакт реле и при повторном смске звонке закрыть его . Cхема распиновки как на картинке

Спасибо

Активируемая по звонку бомба?

1 лайк

Помочь?
это платный раздел форума.

ну не, железка же должна еще второй звонок/СМС принять :slight_smile:

https://aliexpress.ru/item/33003657739.html

Беспроводной GSM SMS Пульт дистанционного управления умный модуль переключателя женский 2-полосный релейный выход для

Призадумался …

Это добавлено для маскировки основного назначения.

1 лайк

Первый звонок - на боевой взвод, второй - бабах :slightly_smiling_face:

1 лайк

ФСБ уже выехали - разберутся …

А может и не бомба. Ворота открывать. Попробовать помочь?
barmaley2m@yandex.ru

Спасибо .В будущем понадобится ) А пока по-пользуюсь с тем что под руками

Да, водородную .Только никому не говорите

Да да ,можете платно помочь?

Те кто могут собрать код напишите в ЛС плз .Спасибо

//#define DEBUG                                     // Для режима отладки нужно раскомментировать эту строку

#ifdef DEBUG                                        // В случае существования DEBUG
#define DEBUG_PRINT(x)       Serial.print (x)       // Создаем "переадресацию" на стандартную функцию
#define DEBUG_PRINTLN(x)     Serial.println (x)
#else                                               // Если DEBUG не существует - игнорируем упоминания функций
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif

#include <SoftwareSerial.h>             // Библиотека програмной реализации обмена по UART-протоколу на пинах отличных от 0 и 1
SoftwareSerial SIM800(9, 8);            // RX, TX - Создаем класс

// Аппаратные настройки ===============================

int     pins[4]         = {5, 4, 3, 2}; // Пины управления реле

// Программные настройки ==============================
String  phones          = "+7928xxxxxxx;+7918xxxxxxx;+7920xxxxxxx";  //  Список телефонов, которые могут управлять устройством. Первый номер - админ

int     actualStatus    =     0;        // Переменная для хранения состояния устройства (0 - все закрыто, 4 - все открыто)
float   balance         =   0.0;        // Переменная для хранения данных о балансе SIM-карты
float   lowLevelBalance =  50.0;        // Переменная порогового значения, при превышении - информирование о балансе
String  tasks[10];                      // Переменная для хранения списка задач к исполнению
bool    executingTask   = false;        // Флаг исполнения отложенной задачи

long    lastUpdate      =     0;        // Переменная хранящая время последней проверки
long    updatePeriod    = 90000;        // 90 сек - Период автоматической проверки наличия сообщений (в миллисекундах, 1000 - 1 сек)
//=====================================================

void setup() {
  for (int i = 0; i < 4; i++) {         // Инициализируем пины реле
    digitalWrite(pins[i], HIGH);        // Так как эта модель реле управляется LOW-сигналом, чтобы не было ложного срабатывания ...
    pinMode(pins[i], OUTPUT);           // ...во время каждого включения, перед установкой режима пина, устанавливаем его значение
  }

  Serial.begin(9600);                   // Скорость обмена данными с компьютером
  SIM800.begin(9600);                   // Скорость обмена данными с модемом
  DEBUG_PRINTLN("Start!");

  delay(5000);                          // Даем время модему завершить инициализацию

  // Отправляем команды инициализации, если все в порядке мигает зеленый индикатор, если нет - красный
  if (sendATCommand("AT", true).indexOf("OK") > -1);  // Команда готовности GSM-модуля
  if (sendATCommand("AT+CLIP=1", true).indexOf("OK") > -1);  // Установка АОН
  if (sendATCommand("AT+CMGF=1", true).indexOf("OK") > -1);  // Установка текстового режима SMS (Text mode)

  sendATCommand("AT+CMGDA=\"DEL ALL\"", true);    // Удаляем все сообщения, чтобы не забивали память МК
  addTask("getBalance");                          // Добавляем задачу - "Запрос баланса"
  // Добавляем задачу - "Отправить SMS админу о включении устройства"
  addTask("sendSMS;" + phones.substring(0, phones.indexOf(";")) + ";Init - OK.\r\nStatus: " + statusToString(actualStatus));

  lastUpdate = millis() + 10000;        // Ближайшая проверка через 10 сек
}


String sendATCommand(String cmd, bool waiting) {  // Функция отправки AT-команды
//  blinkLed(pinGreen, 10);                         // Мигаем зеленым индикатором об отправке данных GSM-модулю
  String _response = "";
  DEBUG_PRINTLN(cmd);                             // Дублируем в Serial отправляемую команду
  SIM800.println(cmd);                            // Отправляем команду модулю
  if (waiting) {                                  // Если нужно ждать ответ от модема...
    _response = waitResponse();                   // Результат ответа сохраняем в переменную
    if (_response.startsWith(cmd)) {              // Если ответ начинается с отправленной команды, убираем её, чтобы не дублировать
      _response = _response.substring(_response.indexOf("\r\n", cmd.length()) + 2);
    }
    DEBUG_PRINTLN(_response);                     // Выводим ответ в Serial
    return _response;                             // Возвращаем ответ
  }
  return "";                                      // Еси ждать ответа не нужно, возвращаем пустую строку
}

String waitResponse() {                           // Функция ожидания ответа от GSM-модуля
  String _buffer;                                 // Переменная для хранения ответа
  long _timeout = millis() + 10000;               // Таймаут наступит через 10 секунд

  while (!SIM800.available() && millis() < _timeout)  {}; //Ждем...
  if (SIM800.available()) {                       // Если есть что принимать...
    _buffer = SIM800.readString();                // ...принимаем
    //DEBUG_PRINTLN("Ok - response");
    return _buffer;                               // и возвращаем полученные данные
  }
  else {                                          // Если таймаут вышел...

    //DEBUG_PRINTLN("Timeout...");
  }
  return "";                                      // и возвращаем пустую строку
}

bool hasmsg = false;                              // Флаг наличия сообщений к удалению

void loop() {
  String _buffer = "";                            // Переменная хранения ответов от GSM-модуля
  if (millis() > lastUpdate && !executingTask) {  // Цикл автоматической проверки SMS, повторяется каждые updatePeriod (90 сек)
    do {
      _buffer = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);  // Отправляем запрос чтения непрочитанных сообщений
      if (_buffer.indexOf("+CMGL: ") > -1) {                      // Если есть хоть одно, получаем его индекс
        int msgIndex = _buffer.substring(_buffer.indexOf("+CMGL: ") + 7, _buffer.indexOf("\"REC UNREAD\"", _buffer.indexOf("+CMGL: "))).toInt();
        char i = 0;                                               // Объявляем счетчик попыток
        do {
          i++;                                                    // Увеличиваем счетчик
          _buffer = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true);  // Пробуем получить текст SMS по индексу
          _buffer.trim();                                         // Убираем пробелы в начале/конце
          if (_buffer.endsWith("OK")) {                           // Если ответ заканчивается на "ОК"
            getActionBySMS(_buffer);                              // Отправляем текст сообщения на обработку
            if (!hasmsg) hasmsg = true;                           // Ставим флаг наличия сообщений для удаления
            sendATCommand("AT+CMGR=" + (String)msgIndex, true);   // Делаем сообщение прочитанным
            break;                                                // Выход из do{}
          }
          else {                                                  // Если сообщение не заканчивается на OK
           
            //Serial.println ("Error answer");
          }
          sendATCommand("\n", true);                              // Перестраховка - вывод новой строки
        } while (i < 10);                                         // Пока попыток меньше 10
        break;
      }
      else {
        lastUpdate = millis() + updatePeriod;                     // Если все обработано, обновляем время последнего обновления
        if (hasmsg) {                                             // Если были сообщения для обработки
          addTask("clearSMS");                                    // Добавляем задание для удаления сообщений
          hasmsg = false;                                         // Сбрасываем флаг наличия сообщений
        }
        break;                                                    // Выходим из цикла
      }
    } while (1);
  }

  if (millis() > lastUpdate + 180000 && executingTask) {          // Таймаут на выполнение задачи - 3 минуты
    //DEBUG_PRINTLN("ExTask-true!");
    sendATCommand("\n", true);
    executingTask = false;                                        // Если флаг не был сброшен по исполению задачи, сбрасываем его принудительно через 3 минуты
  }

  if (SIM800.available())   {                                     // Ожидаем прихода данных (ответа) от модема...
//    blinkLed(pinGreen, 50);                                       // Данные пришли - мигаем зеленым светодиодом

    String msg = waitResponse();                                  // Получаем ответ от модема для анализа
    msg.trim();                                                   // Убираем ненужные пробелы в начале/конце
    DEBUG_PRINTLN(".. " + msg);                                   // ...и выводим их в Serial
//    blinkLed(pinGreen, 50);                                       // Мигаем зеленым светодиодом о приходе данных

    if (msg.startsWith("+CUSD:")) {                               // Если USSD-ответ о балансе
      String msgBalance = msg.substring(msg.indexOf("\"") + 2);   // Парсим ответ
      msgBalance = msgBalance.substring(0, msgBalance.indexOf("\n"));

      balance = getDigitsFromString(msgBalance);                  // Сохраняем баланс
      deleteFirstTask();                                          // Удаляем задачу
      executingTask = false;                                      // Сбрасываем флаг исполнения
      DEBUG_PRINTLN("Balance: " + (String)balance);               // Отчитываемся в Serial
    }
    else if (msg.startsWith("+CMGS:")) {                          // Результат отправки сообщения
      deleteFirstTask();                                          // Удаляем задачу
      executingTask = false;                                      // Сбрасываем флаг исполнения
      DEBUG_PRINTLN("SMS sending - task removed.");               // Отчитываемся в Serial
      addTask("getBalance");                                      // Добавляем задачу запроса баланса
    }
    else if (msg.startsWith("RING")) {                            // При входящем вызове
      sendATCommand("ATH", true);                                 // Всегда сбрасываем
    }
    else if (msg.startsWith("+CMTI:")) {                          // Незапрашиваемый ответ - приход сообщения
      lastUpdate = millis();                                      // Сбрасываем таймер автопроверки наличия сообщений
    }
    else if (msg.startsWith("ERROR")) {                           // Ошибка исполнения команды
      //DEBUG_PRINTLN("Error executing last command.");
      executingTask = false;                                      // Сбрасываем флаг исполнения, но задачу не удаляем - на повторное исполнение
    }
  }

  if (!executingTask && tasks[0] != "") {                         // Если никакая задача не исполняется, и список задач не пуст, то запускаем выполнение.
    showAllTasks();                                               // Показать список задач

    String task = tasks[0];
    if (tasks[0].startsWith("sendSMS")) {                         // Если задача - отправка SMS - отправляем
      task = task.substring(task.indexOf(";") + 1);
      executingTask = true;                                       // Флаг исполнения в true
      sendSMS(task.substring(0, task.indexOf(";")),
              task.substring(task.indexOf(";") + 1));

    }
    else if ((tasks[0].startsWith("getBalance"))) {               // Задача - запрос баланса
      executingTask = true;                                       // Флаг исполнения в true
      sendATCommand("AT+CUSD=1,\"#102#\"", true);                 // Отправка запроса баланса
    }
    else if ((tasks[0].startsWith("clearSMS"))) {                 // Задача - удалить все прочитанные SMS
      sendATCommand("AT+CMGDA=\"DEL READ\"", true);               // Флаг исполнения не устанавливаем - здесь не нужно.
      deleteFirstTask();                                          // Удаляем задачу, сразу после исполнения
    }
    else {
      //DEBUG_PRINTLN("Error: unknown task - " + task);
    }
  }
}

void getActionBySMS(String msg) {                                 // Функция получения действия из SMS
  String msgheader  = "";
  String msgbody    = "";
  String msgphone   = "";
  // Парсим SMS, получаем телефон и текст
  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"));
  msgbody.trim();

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

  if (msgphone.length() > 10 && phones.indexOf(msgphone) > -1) {  // Если номер присутствует в списке номеров
    String result = "";                                           // Обрабатываем это сообщение
    if (msgbody.startsWith("open")) {                             // Если команда "открыть ячейку",

      int blockNum = 0;                                           // Открываем с использованием защитных механизмов
      if (msgbody.length() > 4) {
        blockNum = msgbody.substring(4).toInt();
        if (blockNum > 4 || blockNum < 1) blockNum = -1;
      }

      int blockToOpen = -1;
      int block = blockNum;
//      actualStatus = getStatus();                                 // Получаем актуальный статус
      if (blockNum == -1)  {                                      // Ошибочно указан номер ячейки
        result = "X - Err: " + msgbody.substring(4, 7);
      }
      else if (blockNum == 0) {                                   // Номер блока не указан - автоматическое открывание
        if (actualStatus >= 4) {                                  // Если уже все открыто, то сообщаем об этом
          result = "X";
        }
        else {
          blockToOpen = actualStatus;
          result = "OK auto: " + (String)(actualStatus + 1);
        }
      }
      else { // Открывание по номеру ячейки
        if (blockNum != actualStatus + 1) {
          if (blockNum < actualStatus + 1) {
            result = "X:" + (String)block;
          }
          else {
            result = "X:" + (String)block;
          }
        }
        else {
          blockToOpen = actualStatus;
          result = "OK: " + (String)block;
        }
      }

      //DEBUG_PRINTLN("blockToOpen: " + (String)blockToOpen);
      if (blockToOpen >= 0 && blockToOpen < 4) {                  // Если номер ячейки в допустимых пределах
        digitalWrite(pins[blockToOpen], LOW);                     // Включаем электромагнитный переключатель на 1 секунду
        delay(1000);
        digitalWrite(pins[blockToOpen], HIGH);
      }

//      actualStatus = getStatus();                                 // Получаем актуальный статус
      result += "\r\nStatus: " + statusToString(actualStatus);    // Записываем его в переменную с результатом

      if (balance < lowLevelBalance) {                            // Если баланс ниже заданного предела, добавляем информацию в результат
        result += "\r\nBalance: " + (String)balance;
        }  
      //DEBUG_PRINTLN("result: " + result);

      addTask(getSendSMSTaskString(msgphone, result));            // Добавляем задачу отправки SMS о статусе
      addTask("getBalance");                                      // Добавляем задачу запроса баланса
      showAllTasks();                                             // Выводим список задач
    }
    else if (msgbody.startsWith("force")) {                       // Команда грубого открытия ячейки
      int blockNum = 0;
      if (msgbody.length() > 5) {
        blockNum = msgbody.substring(5).toInt();
        if (blockNum > 4 || blockNum < 1) blockNum = -1;
      }
      if (blockNum > 0) {
        for (int i = 0; i < 4; i++) {
          digitalWrite(pins[blockNum - 1], LOW);
          delay(200);
          digitalWrite(pins[blockNum - 1], HIGH);
          delay(700);
        }
      }
    }
    else if (msgbody.startsWith("status")) {                      // Команда запроса статуса
      result = sendATCommand("AT+CSQ", true);                     // Добавляем информацию о качестве сигнала
      result = result.substring(0, result.indexOf("\n"));


      //DEBUG_PRINTLN("Status: " + statusToString(actualStatus));
      addTask(getSendSMSTaskString(msgphone, "Status: " + statusToString(actualStatus) + "\n" + result)); // Добавляем задачу об отправке SMS со статусом
      addTask("getBalance");                                      // Добавляем задачу о запросе баланса
      showAllTasks();                                             // Выводим все задачи
    }
    else if (msgbody.startsWith("balance")) {                     // Команда запроса баланса
      addTask(getSendSMSTaskString(msgphone, "Balance: " + String(balance)));// Добавляем задачу об отправке SMS с балансом
      addTask("getBalance");                                      // Добавляем задачу о запросе баланса
      showAllTasks();                                             // Выводим все задачи
    }
    else if (msgbody.startsWith("callme")) {                      // Команда осуществить исходящий вызов
      sendATCommand("ATD" + msgphone + ";", true);
    }
    else if (msgbody.startsWith("test")) {                        // Команда тест - открываем поочереди все ячейки
      for (int i = 0; i < 4; i++) {
        digitalWrite(pins[i], LOW);
        delay(500);
        digitalWrite(pins[i], HIGH);
        delay(1000);

      }
    }
    else if (msgbody == "?" || msgbody == "help") {               // Команда получения помощи по командам
      //      String task=getSendSMSTaskString(msgphone, getHelpSMS());
      //      DEBUG_PRINTLN("task: " + task);
      //      addTask(task);

      addTask(getSendSMSTaskString(msgphone, getHelpSMS()));
      addTask("getBalance");
      showAllTasks();
    }
    else if (msgbody.startsWith("checknow")) {                    // Обнулить таймер периодической проверки - проверить сразу
      lastUpdate = millis();
    }

  }
  else {
    //DEBUG_PRINTLN("Unknown phonenumber");
  }

}

String getHelpSMS() {                                             // Текст сообщения с помощью по камандам
  return "Balance, CallMe, Open, Open[1-4], Status, Test, Force";
}
String getSendSMSTaskString( String phone, String msg) {          // Формируем строку задачи отправки SMS
  return "sendSMS;" + phone + ";" + msg;
}


// =================================== Tasks =========================================
void showAllTasks() {                                             // Показать все задачи
  DEBUG_PRINTLN("All Tasks:");
  for (int i = 0; i < 10; i++) {
    if (tasks[i] == "") break;
    DEBUG_PRINTLN("Task " + (String)(i + 1) + ": " + tasks[i]);
  }
}
void deleteFirstTask() {                                          // Удалить первую задачу, остальные передвинуть вверх на 1
  for (int i = 0; i < 10 - 1; i++) {
    tasks[i] = tasks[i + 1];
    if (tasks[i + 1] == "") break;
  }
}
void addTask(String task) {                                       // Добавить задачу в конец очереди
  for (int i = 0; i < 10; i++) {
    if (tasks[i] == task && (task == "clearSMS" || task == "getBalance")) {
      DEBUG_PRINTLN("Task already exists " + (String)(i + 1) + ": " + task);
      return;
    }
    if (tasks[i] == "") {
      tasks[i] = task;
      DEBUG_PRINTLN("Task " + (String)(i + 1) + " added: " + task);
      return;
    }
  }
  DEBUG_PRINTLN("Error!!! Task NOT added: " + task);
}


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

float getDigitsFromString(String str) {                         // Функция выбора цифр из сообщения - для парсинга баланса из USSD-запроса
  bool   flag     = false;
  String digits   = "0123456789.";
  String result   = "";

  for (int i = 0; i < str.length(); i++) {
    char symbol = char(str.substring(i, i + 1)[0]);
    if (digits.indexOf( symbol) > -1) {
      result += symbol;
      if (!flag) flag = true;
    }
    else {
      if (flag) break;
    }
  }
  return result.toFloat();
}

// ================================== Status ============================================


String statusToString(int stat) {               // Статус в строку для отправки в SMS ("2" -> "OO--")
  String result = "";
  for (int i = 0; i < 4; i++) {
    result += i < stat ? "O" : " -";
  }
  return result;
} 
2 лайка

Огромное спасибо !! Я даже не ожидал даже что получится такой громадный код … Но все равно спасибо .
Хотел бы еще уточнить некоторые строки которые не совсем ясны мне .Буду рад если поясните

Строка 12 :

У меня используется модуль Sim808 , и там пины до 6ти .соответственно нужно указывать номера пинов под Рх Тх?

Строка 16 .

Пин управления реле разве не один ? под марком S

От строка 92 до 193 не понял .Можно ли обойтись без функций показа баланса и миганий ,поскольку за этом никто не будет следить . Плата установится под закрытое место ,куда заглянут раз в месяц , и баланс будет расчитываться тупо ежемесячно .

Общий вопрос : Чтобы упростить задачу защиты срабатывания датчика от случайных телефонных звонков и смс .можно ли команду срабатывания привязать на какое то кодовое слово, типа Go On , Go Off
Еще одна функция оповещения по смс о срабаывании реле ,типа Now On или Now OFF

Спасибо заранее

Дайте воды попить, а то так жрать хочется, что переночевать негде?

2 лайка

@Anton_Kos1987 сам виноват. Влез на форум и, не дав себе труда разобраться что тут и где, вывалил готовый код в коммерческом разделе. Реально покоробило, когда увидел.

1 лайк

причем похоже не его код… судя по тому, сколько там лишнего, того что ТС и не просил

1 лайк
Спойлер

SIM 800L БЕСПЛАТНОЕ ВКЛЮЧЕНИЕ НАГРУЗКИ ПО СОТОВОМУ - YouTube

Спойлер

ТРИ В ОДНОМ SIM 800L ВКЛЮЧЕНИЕ НАГРУЗКИ С ДОЗВОНАМИ И БЕЗ И ПРОСТЕНЬКАЯ СИГНАЛИЗАЦИЯ - YouTube

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