Сигнализация / удаленный мониторинг за датчиками по GSM/GPRS

Введение:

В этом уроке мы создадим систему удаленного мониторинга и охраны дома, используя GSM/GPRS Shield.

При выполнении одного из заданных сценариев модуль будет отправлять СМС или звонить Вам на телефон, а в режиме ожидания по запросу сможет отправлять СМС с текущим состоянием системы.

Видео:

Нам понадобится:

    Для реализации проекта нам необходимо установить библиотеки:

    • iarduino_GSM — для работы с GSM/GPRS Shield;
    • OneWhire — для работы с датчиками фирмы Dallas;
    • DallasTemperature — для работы с цифровыми термометрами DS18B20;
    • SoftwareSerial — библиотека входит в базовый набор Arduino IDE и не требует установки;

    О том, как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.

    Описание работы системы удалённого управления: 

    • После подачи питания дождитесь получения смс с уведомлением о том, что инициализация прошла успешно и модем GSM зарегистрировался в сети. После этого устройство готово к работе.
    • Устройство может принимать сообщения с командой "ОТЧЁТ";
    • После правильно написанной и отправленной СМС дождитесь обратного сообщения с данными об актуальном состоянии системы;
    • Так же, в устройстве есть несколько сценариев работы с датчиками:
      • При сработке любого из датчиков на телефон абонента отправляется СМС с уведомлением и актуальным значением датчика;
      • При сработке некоторых особо важных датчиков устройство отправляет СМС с уведомлением, а затем совершает звонок на указанный в коде номер, благодаря чему абонент может услышать, что происходит вокруг устройства.

      Схема сборки:

    Arduino / Piranha UNO:

    Batery Shield:

    Установите Battery Shield на Arduino / Piranha UNO:
    Во время установки Battery Shield должен быть в выключенном состоянии.

    GSM/GPRS Shield:

    На Battery Shield установите GSM/GPRS Shield A6:

    На плате GSM/GPRS Shield A6 имеется слот для SIM-карт и переключатель UART. Установите SIM-карту в слот, выберите положение переключателя RX-7/TX-8.

    Trema Shield:

    На GSM/GPRS Shield A6 установите Trema Shield:

    Гарнитура:

    Установите гарнитуру в GSM/GPRS Shield A6.

    Trema-модуль Цифровой термометр:

    Подключите Trema-модуль Цифровой термометр к  Trema Shield.

    Trema-модуль Датчик газа:

    Подключите Trema-модуль Датчик газа к  Trema Shield.

    Цифровой термометр (герметичный):

    Подключите цифровой термометр (герметичный) к  Trema Shield.

    Обратите внимание, что между информационным проводом (жёлтый) и проводом питания 5В (красный) установлен резистор 10кОм.

    Магнитный извещатель (геркон):

    Подключите магнитный извещатель (геркон) к Trema Shield.

    Обратите внимание, что от информационного провода (жёлтый) через резистор 10кОм подключается провод GND (чёрный).

    Код программы (скетч):

                                  // БИБЛИОТЕКИ
    #include        <iarduino_GSM.h>                                                                                              // Подключаем библиотеку iarduino_GSM для работы с GSM/GPRS Shield.
    #include        <SoftwareSerial.h>                                                                                            // Подключаем библиотеку SoftwareSerial для программной реализации шины UART.
    #include        <OneWire.h>                                                                                                   // Подключаем библиотеку OneWire для работы с оборудованием фирмы Dallas
    #include        <DallasTemperature.h>                                                                                         // Подключаем библиотеку DallasTemperature для работы с цифровым термометром DS18B20
                                  // ОБЪЕКТЫ ДЛЯ РАБОТЫ С ДАТЧИКАМИ ТЕМПЕРАТУРЫ
    OneWire oneWire_in(2);                                                                                                        // Указываем вывод, к которому подключен термометр внутри помещения
    OneWire oneWire_out(3);                                                                                                       // Указываем вывод, к которому подключен термометр снаружи помещения
    DallasTemperature sensor_inhouse(&oneWire_in);                                                                                // Создаём объект sensor_inhouse для работы с термометром внутри помещения
    DallasTemperature sensor_outhouse(&oneWire_out);                                                                              // Создаём объект sensor_outhouse для работы с термометром снаружи помещения
                                  // ОБЪЕКТЫ ДЛЯ РАБОТЫ С GSM/GPRS МОДУЛЕМ
    iarduino_GSM    gsm;                                                                                                          // Создаём объект gsm для работы с функциями и методами библиотеки iarduino_GSM.
    SoftwareSerial  softSerial(7, 8);                                                                                             // Создаём объект softSerial для работы по программной шине UATR, указывая выводы RX и TX платы Arduino (выводы 7 и 8)
                                  // ПЕРЕМЕННЫЕ
    String          Text;                                                                                                         // Переменная типа String для хранения текстовой информации
    String          Text_alarm;                                                                                                   // Переменная типа String для хранения текстовой информации? для отправки в случае тревоги
    String          strSMStxt;                                                                                                    // Переменная типа String для работы с поиском символа в строке
    char            SMStxt[161];                                                                                                  // Объявляем строку для хранения текста принятых SMS сообщений.
    char            SMSnum[13];                                                                                                   // Объявляем строку для хранения номера отправителя SMS сообщений.
    char            number[13]    = "7_ВАШ_НОМЕР_ТЕЛЕФОНА";                                                                       // Зададим номер, с которым будет работать модуль
    char*           Func          = "ОТЧЁТ";                                                                                      // Объявляем массив для хранения указателя на строку
    char            Pins[]        =  {A0, 4, 5};                                                                                  // Массив с номерами выводов устройств
    int8_t          MIN_TEMP_IN   = 15;                                                                                           // Минимальная температура срабатывания для термометра внутри помещения
    int8_t          MAX_TEMP_IN   = 28;                                                                                           // Максимальная температура срабатывания для термометра внутри помещения
    int8_t          MIN_TEMP_OUT  = 10;                                                                                           // Минимальная температура срабатывания для термометра снаружи помещения
    int8_t          MAX_TEMP_OUT  = 35;                                                                                           // Максимальная температура срабатывания для термометра снаружи помещения
    int16_t         MAX_GAS_VALUE = 450;                                                                                          // Максимальное значение концентрации газа
    uint32_t        delta_time    = 100000;                                                                                       // Время, по истечении которого производится повторная отправка СМС
    uint32_t        waiting_time  = 5000;                                                                                         // Время между отправкой СМС и совершением тревожного звонка
    uint32_t        dial_waiting  = 30000;                                                                                        // Время разговора при тревожном звонке
    uint32_t        dial_time     = 0;                                                                                            // Таймер для тревожного звонка
    uint32_t        temp1_time    = 0;                                                                                            // Таймер для датчика температуры внутри помещения на повторную отправку СМС
    uint32_t        temp2_time    = 0;                                                                                            // Таймер для датчика температуры снаружи помещения на повторную отправку СМС
    uint32_t        gas_time      = 0;                                                                                            // Таймер для датчика газа на повторную отправку СМС
    uint32_t        motion_time   = 0;                                                                                            // Таймер для датчика движения на повторную отправку СМС
    uint32_t        gerkon_time   = 0;                                                                                            // Таймер для датчика состояния на повторную отправку СМС
    uint32_t        call          = 0;                                                                                            // Таймер для совершения тревожного звонка
    
    
    void setup() {
      sensor_inhouse.begin();                                                                                                     // Инициируем работу с термометром внутри помещения
      sensor_outhouse.begin();                                                                                                    // Инициируем работу с термометром снаружи помещения
      gsm.begin(softSerial);                                                                                                      // Инициируем работу GSM/GPRS Shield, указывая объект шины UART.
      while (gsm.status() != GSM_OK) {delay(1000);}                                                                               // Ждём завершения регистрации модема в сети оператора связи.
      pinMode(Pins[0], INPUT);                                                                                                    // Настройка вывода на работу в режиме ВХОД
      pinMode(Pins[1], INPUT);                                                                                                    // Настройка вывода на работу в режиме ВХОД
      // Установка кодировки для символов Кириллицы:
      gsm.TXTsendCodingDetect("п");                                                                                               // Выполняем автоопределение кодировки скетча для отправки текста на Русском языке.
      // Отправка сообщения об удачном запуске:
      gsm.SMSsend( F("Инициализация прошла успешно."), number);                                                                   // Данная строка будет отвечать отправителю указанным SMS сообщением.
    }
    
    void loop () {
      Text_alarm = "";                                                                                                            // Очищаем строку
      Text = "";                                                                                                                  // Очищаем строку
      //==========================================================================================================================//
                                    // ДАТЧИК ГАЗА
      if (analogRead(Pins[0]) >= MAX_GAS_VALUE) {                                                                                 // Проверяем, не превышена ли концентрация газа и
        if ((gas_time + delta_time) < millis() || gas_time == 0) {                                                                // если превышена, то проверяем, чтобы сообщения отправлялись не чаще, чем 1 раз в delta_time
          gas_time = millis();                                                                                                    // Обновляем счётчик
          Text_alarm = "Превышена концентрация газа.\r\nЗначение = " + analogRead(Pins[0]);                                       // Формируем текст сообщения
          gsm.SMSsend(Text, number);                                                                                              // Отправляем СМС с текстом
        }
      }
      Text = Text + "Газ: " + analogRead(Pins[0]) + "ppm";                                                                        // добавляем в строку текст, значение уровня концентрации газа и
      delay(10);                                                                                                                  // ждём 10мс
      //==========================================================================================================================//
                                    // ДАТЧИК ТЕМПЕРАТУРЫ ВНУТРЕННИЙ
      sensor_inhouse.requestTemperatures();                                                                                       // Запрос значения термометра внутри помещения
      if (sensor_inhouse.getTempCByIndex(0) <= MIN_TEMP_IN || sensor_inhouse.getTempCByIndex(0) >= MAX_TEMP_IN) {                 // Проверяем, не выходит ли полученное значение за установленные границы и
        if ((temp1_time + delta_time) < millis() || temp1_time == 0) {                                                            // если выходит, то проверяем, чтобы сообщения отправлялись не чаще, чем 1 раз в delta_time
          temp1_time = millis();                                                                                                  // Обновляем счётчик
          Text_alarm = "Пороговое изменение температуры внутри.\r\nЗначение = " + String (sensor_inhouse.getTempCByIndex(0));     // Формируем текст сообщения
          gsm.SMSsend(Text, number);                                                                                              // Отправляем СМС с текстом
        }
      }
      Text = Text + "\r\nТвнут: " + sensor_inhouse.getTempCByIndex(0);                                                            // добавляем в строку текст, значение термометра и
      delay(10);                                                                                                                  // ждём 10мс
      //==========================================================================================================================//
                                    // ДАТЧИК ТЕМПЕРАТУРЫ ВНЕШНИЙ
      sensor_outhouse.requestTemperatures();                                                                                      // Запрос значения термометра снаружи помещения
      if (sensor_outhouse.getTempCByIndex(0) <= MIN_TEMP_OUT || sensor_outhouse.getTempCByIndex(0) >= MAX_TEMP_OUT) {             // Проверяем, не выходит ли полученное значение за установленные границы и
        if ((temp2_time + delta_time) < millis() || temp2_time == 0) {                                                            // если выходит, то проверяем, чтобы сообщения отправлялись не чаще, чем 1 раз в delta_time
          temp2_time = millis();                                                                                                  // Обновляем счётчик
          Text_alarm = "Пороговое изменение температуры снаружи.\r\nЗначение = " + String (sensor_outhouse.getTempCByIndex(0));;  // Формируем текст сообщения
          gsm.SMSsend(Text, number);                                                                                              // Отправляем СМС с текстом
        }
      }
      Text = Text + "\r\nТвнеш: " + sensor_outhouse.getTempCByIndex(0);                                                           // добавляем в строку текст, значение термометра и
      delay(10);                                                                                                                  // ждём 10мс
      //==========================================================================================================================//
                                    // ДАТЧИК ДВИЖЕНИЯ
      if (digitalRead(Pins[1])) {                                                                                                 // Проверяем, не было ли сработки датчика движения и
        if ((motion_time + delta_time) < millis() || motion_time == 0) {                                                          // если было, то проверяем, чтобы сообщения отправлялись не чаще, чем 1 раз в delta_time
          motion_time = millis();                                                                                                 // Обновляем счётчик
          gsm.SMSsend("Замечено движение!", number);                                                                              // Отправляем СМС с текстом
          if ((call + waiting_time) < millis() || call == 0 ) {                                                                   // Ждём, пока не пройдёт время waiting_time, прежде чем совершим тревожный звонок
            gsm.SOUNDdevice(GSM_HEADSET);                                                                                         // Укажем использование модулем гарнитуры
            // Закомментируйте строки 101-106 и раскомментируйте строку 107, если вам не требуется ограничение тревожного звонка по времени
            if (gsm.CALLdial(number)) {                                                                                           // Если звонок инициирован, то
              while (gsm.CALLstatus() != GSM_CALL_ACTIVE) {}                                                                      // ждём, пока статус звонка не изменится на GSM_CALL_ACTIVE
              dial_time = millis();                                                                                               // Обновляем счётчик
              while ((dial_time + dial_waiting) > millis() ) {}                                                                   // Ждём время dial_waiting, прежде чем автоматически разорвём соединение
              gsm.CALLend();                                                                                                      // Разрываем соединение
            }
            //gsm.CALLdial(number);                                                                                               // Выполняем набор номера
          }
        }
      }
      Text = Text + "\r\nДвижение: -";                                                                                            // добавляем в строку текст, значение датчика движения и
      delay(10);                                                                                                                  // ждём 10мс
      //==========================================================================================================================//
                                    // ДАТЧИК СОСТОЯНИЯ (ГЕРКОН)
      if (!digitalRead(Pins[2])) {                                                                                                // Проверяем, не было ли сработки датчика состояния и
        if ((gerkon_time + delta_time) < millis() || gerkon_time == 0) {                                                          // если было, то проверяем, чтобы сообщения отправлялись не чаще, чем 1 раз в delta_time
          gerkon_time = millis();                                                                                                 // Обновляем счётчик
          gsm.SMSsend("Окно открыто!", number);                                                                                   // Отправляем СМС с текстом
          if ((call + waiting_time) < millis() || call == 0 ) {                                                                   // Ждём, пока не пройдёт время waiting_time, прежде чем совершим тревожный звонок
            gsm.SOUNDdevice(GSM_HEADSET);                                                                                         // Укажем использование модулем гарнитуры
            // Закомментируйте строки 128-133 и раскомментируйте строку 134, если вам не требуется ограничение тревожного звонка по времени
            if (gsm.CALLdial(number)) {                                                                                           // Если звонок инициирован, то
              while (gsm.CALLstatus() != GSM_CALL_ACTIVE) {}                                                                      // ждём, пока статус звонка не изменится на GSM_CALL_ACTIVE
              dial_time = millis();                                                                                               // Обновляем счётчик
              while ((dial_time + dial_waiting) > millis() ) {}                                                                   // Ждём время dial_waiting, прежде чем автоматически разорвём соединение
              gsm.CALLend();                                                                                                      // Разрываем соединение
            }
            //gsm.CALLdial(number);                                                                                               // Выполняем набор номера
          }
        }
      }
      Text = Text + "\r\nОкно: +";                                                                                                // добавляем в строку текст и
      delay(10);                                                                                                                  // ждём 10мс
      //==========================================================================================================================//
                                    // ЗАПРОС ОТЧЁТА
      if (millis() % 1000 < 100) {                                                                                                // Выполняем код в теле оператора if первые 100 мс каждой секунды.
        delay(100);                                                                                                               // Устанавливаем задержку в 100 мс, чтоб не выполнить код более 1 раза за секунду.
        if (gsm.SMSavailable()) {                                                                                                 // Функция SMSavailable() возвращает количество входящих непрочитанных SMS сообщений.
          gsm.SMSread(SMStxt, SMSnum);                                                                                            // Читаем SMS сообщение в ранее объявленные переменные (текст SMS сообщения, адрес отправителя, дата отправки, идентификатор SMS, количество SMS, номер SMS).
          if (!strcmp(number, SMSnum)) {                                                                                          // Проверим, что все символы в двух строках совпадают (при совпадении функция strcmp возвращает 0)
            strSMStxt = SMStxt;                                                                                                   // Присваиваем массиву strSMStxt значения массива SMStxt для дальнейшей проверки на совпадения
            if (strSMStxt.indexOf(Func) != -1 ) {                                                                                 // Если совпадение найдено, то
              gsm.SMSsend(Text, number);                                                                                          // отправляем сообщение с отчётом
            } else {                                                                                                              // Если текст пришёл не верный, то
              gsm.SMSsend(F("Ошибка в тексте!"), number);                                                                         // отправляем об этом сообщение
            }
          }
        }
      }
      //==========================================================================================================================//
                                    // ОТВЕТ НА ВХОДЯЩИЙ ЗВОНОК
      if (gsm.CALLavailable(SMSnum)) {                                                                                            // Функция CALLavailable() возвращает true если есть входящий дозванивающийся вызов. В качестве аргумента функции можно указать строку в которую будет записан адрес (номер) вызывающего абонента.
        if (!strcmp(number, SMSnum)) {                                                                                            // Проверим, что все символы в двух строках совпадают (при совпадении функция strcmp возвращает 0)
          gsm.SOUNDdevice(GSM_HEADSET);                                                                                           // Использовать гарнитуру для ввода/вывода звука.
          gsm.CALLup();                                                                                                           // Отвечаем на вызов. Если нужно сбросить вызов, то обращаемся к функции CALLend().
          while (gsm.CALLavailable()) {}                                                                                          // Цикл выполняется пока входящий дозванивающийся вызов не сменит статус на "активный голосовой вызов" или любой другой.
        }
      }
    }

    Алгоритм работы скетча:

    До кода void setup() определяются номера выводов, объявляются переменные и функции, подключаются библиотеки, и создаются объекты для работы с ними.

    Перед загрузкой скетча не забудьте задать в переменной number[] номер телефона, куда будет приходить смс-уведомление о пройденной идентификации!

    В коде void setup() конфигурируются выбранные выводы, инициируется работа GSM/GPRS Shield, выполняется цикл ожидания готовности GSM/GPRS Shield к работе (регистрация в сети оператора). И, после выполнения всех указанных действий, выполняется оповещение о готовности к работе, путем отправки смс на указанный номер.

    Код void loop() выполняется в цикле. При получении СМС или при наступлении события, указанного в сценарии кода, устройство отправляет сообщение абоненту или совершает тревожный звонок. Чтобы после наступления события модуль не начал непрерывно отправлять сообщения или совершать звонки, в код была добавлена временная задержка delta_time, в течении которой модуль игнорирует повторные сработки. По истечении этого времени, если ничего не изменилось, модуль повторно отправит СМС или совершит тревожный звонок.

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

    Сам код можно разделить на блоки:

    Датчик газа:

    Задав граничное значение в переменной MAX_GAS_VOLUME в самом начале скетча, тем самым мы устанавливаем правила отправки СМС от модуля пользователю.

    При достижении этого значения модуль отправит на указанный в переменной number номер смс с уведомлением о том, что концентрация газа превышена.

    Если же концентрация в норме, то данные будут внесены в строку Text, которая при запросе пользователя будет выслана ему по СМС вместе с показателями других модулей.

    Датчик температуры внутренний:

    Указав в переменных MIN_TEMP_IN и MAX_TEMP_IN границы допустимых температур, настроим модуль на работу с цифровым термометром, расположенным внутри помещения.

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

    Если температура внутри помещения в норме, то данные будут внесены в строку Text, которая при запросе пользователя будет выслана ему по СМС вместе с показателями других модулей.

    Датчик температуры внешний:

    Указав в переменных MIN_TEMP_OUT и MAX_TEMP_OUT границы допустимых температур, настроим модуль на работу с цифровым термометром, расположенным снаружи помещения.

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

    Если температура снаружи помещения в норме, то данные будут внесены в строку Text, которая при запросе пользователя будет выслана ему по СМС вместе с показателями других модулей.

    Датчик движения:

    Проверяем, нет ли движения в радиусе действия датчика:

    • Если движение замечено, то модуль отправляет СМС абоненту на номер, указанный в переменной number, далее ждёт время waiting_timeи после этого совершает тревожный звонок на тот же номер.
    • В переменной gsm.SOUNDdevice указан параметр GSM_HEADSET, что означает, что на стороне модуля установлена гарнитура.
    • Тревожный звонок можно настроить:
      • Модуль совершает тревожный звонок "до победного", пока абонент не снимет трубку или не начнёт работать автоответчик;
      • Модуль совершает тревожный звонок, а после того, как трубка будет снята, ограничит разговор на время, указанное в переменной diall_waiting;
    • Если движение не замечено, то данные будут внесены в строку Text, которая при запросе пользователя будет выслана ему по СМС вместе с показателями других модулей.

    Датчик состояния(геркон):

    Проверяем, нет ли размыкания датчика:

    • Если датчик разомкнут, то модуль отправляет СМС абоненту на номер, указанный в переменной number, далее ждёт время waiting_timeи после этого совершает тревожный звонок на тот же номер. 
    • В переменной gsm.SOUNDdevice указан параметр GSM_HEADSET, что означает, что на стороне модуля установлена гарнитура.
    • Тревожный звонок можно настроить:
      • Модуль совершает тревожный звонок "до победного", пока абонент не снимет трубку или не начнёт работать автоответчик;
      • Модуль совершает тревожный звонок, а после того, как трубка будет снята, ограничит разговор на время, указанное в переменной diall_waiting;
    • Если датчик замкнут, то данные будут внесены в строку Text, которая при запросе пользователя будет выслана ему по СМС вместе с показателями других модулей.

    Запрос отчёта:

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

    • Если номер совпадает, то модуль проверяет текст сообщения:
      • Если в тексте сообщения указана команда из переменной Func, то модуль отправляет ответное СМС с полным отчётом по всем датчикам;
      • Если в тексте СМС ошибка, то модуль в ответном СМС уведомит об этом;
    • Если номер не совпадает, то модуль будет игнорировать текст СМС;

    Ответ на входящий звонок:

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

    В переменной gsm.SOUNDdevice указан параметр GSM_HEADSET, что означает, что на стороне модуля установлена гарнитура.

    Для того, чтобы модуль ответил на входящий звонок, номер, с которого совершают вызов, должен совпадать с номером, указанным в переменной number.

    Ссылки:

    Обсуждение