Введение:
В этом уроке мы создадим систему удаленного управления домом по смс, используя GSM/GPRS Shield.
При получении смс устройство будет выполнять одну из указанных в смс функций, после чего уведомит вас об этом в ответной смс.
Видео:
Нам понадобится:
- 1х Piranha UNO
- 1х GSM/GPRS Shield;
- 1х Battery Shield;
- 2х Реле;
- 2х Силовой ключ;
- 1х Линейный привод 12В;
- 1х Светодиодная лента 12В;
- 1х Источник питания 12В;
- 1х Вентилятор(кулер) 12В;
- 2х Лампочка;
Для реализации проекта нам необходимо установить библиотеки:
- iarduino_GSM- для работы с GSM/GPRS Shield;
- Библиотеки 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 A9:
На плате GSM/GPRS Shield A9 имеется слот для SIM-карт и переключатель UART. Установите SIM-карту в слот, выберите положение переключателя RX-7/TX-8.

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

Линейный привод:
Подключим линейный привод к Trema Shield. Для этого необходимо 2 электромеханических реле подключить к выводу 4.
После этого установить перемычки согласно рисунку.
Далее подключить к реле линейный привод и подвести внешнее питание 12В.

Лампочки:
Подключите к выводу 2 и 3 Trema Shield 2 твердотельных реле.
Далее согласно схеме подключите к реле лампочки и питание 220В.
Будьте предельно внимательны и осторожны!

Светодиодная лента:
Подключите к 6 выводу Trema Shield Trema-модуль Силовой ключ, а к нему подключите светодиодную ленту, пустив провод питания ленты (красный) напрямую к источнику питания 12В, а провод GND ленты (чёрный) в разрыв через Trema-модуль Силовой ключ.

Вентилятор(кулер):
Подключите к 5 выводу Trema Shield Trema-модуль Силовой ключ, а к нему подключите вентилятор (кулер), пустив провод питания вентилятора (красный) напрямую к источнику питания 12В, а провод GND вентилятора (чёрный) в разрыв через Trema-модуль Силовой ключ.

Код программы (скетч):
В скетче используются библиотеки iarduino_GSM и SoftwareSerial.
              // БИБЛИОТЕКИ
#include       <Wire.h>                                                                               // Подключаем библиотеку для работы с аппаратной шиной I2C, до подключения библиотек iarduino_I2C_Encoder и iarduino_I2C_DSL.
#include       <SoftwareSerial.h>                                                                     // Подключаем библиотеку SoftwareSerial для программной реализации шины UART.
#include       <iarduino_GSM.h>                                                                       // Подключаем библиотеку iarduino_GSM для работы с GSM/GPRS Shield.
#define pinPWR 7                                                                                      // Вывод Arduino используемый для включения  GSM/GPRS Shield.
#define pinRX  8                                                                                      // Вывод Arduino RX подключаемый к выводу TX GSM/GPRS Shield.
#define pinTX  9                                                                                      // Вывод Arduino TX подключаемый к выводу RX GSM/GPRS Shield.
iarduino_GSM    gsm(pinPWR);                                                                          // Создаём объект gsm для работы с функциями и методами библиотеки iarduino_GSM.
SoftwareSerial  softSerial(pinRX, pinTX);                                                             // Создаём объект softSerial для работы по программной шине UATR, указывая выводы RX и TX платы Arduino (выводы 7 и 8)
              // ПЕРЕМЕННЫЕ
uint8_t         Sum        = 0;                                                                       // Переменная для хранения процентного значения ШИМ-сигнала
              // Для отправки СМС о удачном запуске устройства, укажите в строке ниже номер телефона без пробелов.
char            SMSnum[13] = "7_ВАШ_НОМЕР_ТЕЛЕФОНА";                                                  // Объявляем строку для хранения номера отправителя SMS сообщений.
char            SMStxt[161];                                                                          // Объявляем строку для хранения текста принятых SMS сообщений.
String          strSMStxt;                                                                            // переменная типа String для более удобной работы
uint8_t         flgFunc;                                                                              // флаг наличия действия
uint8_t         flgDev;                                                                               // флаг наличия устройства
uint8_t         flgPWM;                                                                               // флаг наличия ШИМ
uint8_t         lvlPWM;                                                                               // Переменная количества символов в строке
const char*     Func[2][5] = {{"ВКЛЮЧИТЬ", "ВЫКЛЮЧИТЬ"},                                              // Двумерный массив с функциями и устройствами
                              {"СВЕТ КУХНЯ" , "СВЕТ КОМНАТА", "ДВЕРЬ", "ВЕНТИЛЯТОР", "ПОДСВЕТКА"}};   // 
const char      Pins[]     =  {     2,             3,            4,         5,           6       };   // Массив с номерами выводов устройств
                                                                                                      // 
void setup() {                                                                                        //
                // Инициируем GSM/GPRS Shield и проверяем его готовность к работе:
  gsm.begin(softSerial);                                                                              // Инициируем работу GSM/GPRS Shield, указывая объект шины UART.
  while (gsm.status() != GSM_OK) { delay(1000); }                                                     // Ждём завершения регистрации модема в сети оператора связи.
                // Установка кодировки для символов Кириллицы:
  gsm.TXTsendCodingDetect("п");                                                                       // Выполняем автоопределение кодировки скетча для отправки текста на Русском языке.
                // Отправка сообщения об удачном запуске:
  gsm.SMSsend( F("Инициализация прошла успешно."), SMSnum);                                           // Данная строка будет отвечать отправителю указанным SMS сообщением.
                // Настраиваем выводы
  pinMode(Pins[0],   OUTPUT);                                                                         // настройка вывода на работу в режиме выхода
  pinMode(Pins[1],   OUTPUT);                                                                         // настройка вывода на работу в режиме выхода
  pinMode(Pins[2],   OUTPUT);                                                                         // настройка вывода на работу в режиме выхода
  pinMode(Pins[3],   OUTPUT);                                                                         // настройка вывода на работу в режиме выхода
  pinMode(Pins[4],   OUTPUT);                                                                         // настройка вывода на работу в режиме выхода
  digitalWrite(Pins[0], LOW);                                                                         // устанавливаем на выходе значение сигнала равным LOW
  digitalWrite(Pins[1], LOW);                                                                         // устанавливаем на выходе значение сигнала равным LOW
  digitalWrite(Pins[2], LOW);                                                                         // устанавливаем на выходе значение сигнала равным LOW
  digitalWrite(Pins[3], LOW);                                                                         // устанавливаем на выходе значение сигнала равным LOW
  digitalWrite(Pins[4], LOW);                                                                         // устанавливаем на выходе значение сигнала равным LOW
  flgFunc = 20;                                                                                       // Сбрасываем флаг
  flgDev  = 20;                                                                                       // Сбрасываем флаг
  flgPWM  =  0;                                                                                       // Сбрасываем флаг
}                                                                                                     // 
                                                                                                      // 
void loop () {                                                                                        // 
  if (millis() % 1000 < 100) {                                                                        // Выполняем код в теле оператора if первые 100 мс каждой секунды.
    delay(100);                                                                                       // Устанавливаем задержку в 100 мс, чтоб не выполнить код более 1 раза за секунду.
    if (gsm.SMSavailable()) {                                                                         // Функция SMSavailable() возвращает количество входящих непрочитанных SMS сообщений.
      gsm.SMSread(SMStxt, SMSnum);                                                                    // Читаем SMS сообщение в ранее объявленные переменные (текст SMS сообщения, адрес отправителя, дата отправки, идентификатор SMS, количество SMS, номер SMS).
      strSMStxt = SMStxt;                                                                             // Присваиваем массиву atrSMStxt значения массива SMStxt для дальнейшей проверки на совпадения
      for (int m = 0; m < (sizeof(Func[0]) / 2); m++) {                                               // проверяем в цикле, совпадает ли команда из массива с тем, что пришло в СМС
        if (strSMStxt.indexOf(Func[0][m]) > -1 && *Func[0][m] != 0) {                                 // если совпадения есть, то
          flgFunc = m;                                                                                // присваиваем флагу порядковый номер совпавшего слова из массива Func
          for (int i = 0; i < (sizeof(Func[1]) / 2); i++) {                                           // проверяем в цикле, совпадает ли имя устройства из массива с тем, что пришло в СМС
            if (strSMStxt.indexOf(Func[1][i]) > -1 && *Func[1][i] != 0) {                             // если совпадения есть и это не пустая строка, то
              flgDev = i;                                                                             // присваиваем флагу порядковый номер совпавшего слова из массива Device
              if (strchr(SMStxt, '%')) {                                                              // проверяем, есть ли в тексте СМС символ %
                flgPWM = 1;                                                                           // и если есть, то устанавливаем флаг
              }                                                                                       //
            }                                                                                         //
          }                                                                                           //
        }                                                                                             //
      }                                                                                               //
      if (flgPWM == 1) {                                                                              // если установлен флаг flgPWM, то
        lvlPWM = uint8_t(strchr(SMStxt, '%' ) - SMStxt);                                              // определяем количество символов в строке до совпадения с символом %
        if (SMStxt[lvlPWM - 1] >= '0' && SMStxt[lvlPWM - 1] <= '9') {                                 // Проверяем, является ли символ, расположенный в строке на 1 позицию левее символа %, цифрой от 0 до 9, и если да, то
          Sum = uint8_t(SMStxt[lvlPWM - 1] - '0');                                                    // прибавляем эту цифру к переменной (единицы)
          if (SMStxt[lvlPWM - 2] >= '0' && SMStxt[lvlPWM - 2] <= '9') {                               // Проверяем, является ли символ, расположенный в строке на 2 позиции левее символа %, цифрой от 0 до 9, и если да, то
            Sum += uint8_t((SMStxt[lvlPWM - 2] - '0') * 10);                                          // прибавляем эту цифру к переменной, умножив на 10 (десятки)
            if (SMStxt[lvlPWM - 3] > '0' && SMStxt[lvlPWM - 3] <= '1') {                              // Проверяем, является ли символ, расположенный в строке на 3 позиции левее символа %, цифрой от 0 до 1, и если да, то
              Sum += uint8_t((SMStxt[lvlPWM - 3] - '0') * 100) ;                                      // прибавляем эту цифру к переменной, умножив на 100 (сотни)
            } else                                                                                    // иначе проверяем, что
              if (SMStxt[lvlPWM - 3] >= '2' && SMStxt[lvlPWM - 3] <= '9') {                           // число "сотен" не больше 1, и если больше то
                flgPWM = 0;                                                                           // сбрасываем флаг ШИМ
              }                                                                                       // 
          }                                                                                           //
        }                                                                                             //
      }                                                                                               //
      if (flgFunc != 20) {                                                                            // если флаг flgFunc установлен, то
        switch (flgFunc) {                                                                            // проверяем значение флага flgFunc с определёнными в операторе case
          case 0:                                                                                     // Если 0 - значит указано действие ВКЛЮЧИТЬ
            if (flgDev != 20) {                                                                       // Если установлен флаг наличия устройства, то
              if (flgPWM == 1) {                                                                      // проверяем флаг ШИМ. Если он установлен, то
                uint8_t mapPWM = map(Sum, 0, 100, 0, 255);                                            // переопределяем множество для ШИМ и
                analogWrite(Pins[flgDev], mapPWM );                                                   // подаём ШИМ-сигнал на вывод и
                gsm.SMSsend(F("Процент задан!"), SMSnum);                                             // отправляем сообщение об успешном выполнении.
                Sum    = 0;                                                                           // сбрасываем количество процентов для задания ШИМ-сигнала после выполнения
                flgPWM = 0;                                                                           // сбрасываем флаг ШИМ после выполнения
              }                                                                                       //
              else {                                                                                  // Если же флага ШИМ нет, то
                digitalWrite(Pins[flgDev], HIGH);                                                     // подаём высокий сигнал на вывод для включения и
                gsm.SMSsend(F("Устройство включено!"), SMSnum);                                       // отправляем сообщение об успешном выполнении.
              }                                                                                       //
              flgDev = 20;                                                                            // сбрасываем флаг устройства после выполнения
            } else {                                                                                  // если в СМС не указано устройство, то
              gsm.SMSsend(F("Что включить?"), SMSnum);                                                // отправляем об этом сообщение
            }                                                                                         // 
            flgFunc = 20;                                                                             // сбрасываем флаг действия после выполнения
            break;                                                                                    //
          case 1:                                                                                     // Если 1 - значит указано действие ВЫКЛЮЧИТЬ
            if (flgDev != 20) {                                                                       // Если установлен флаг наличия устройства, то
              digitalWrite(Pins[flgDev], LOW);                                                        // подаём низкий сигнал на вывод для выключения
              gsm.SMSsend(F("Устройство выключено!"), SMSnum);                                        // и отправляем сообщение об успешном выполнении.
              flgDev = 20;                                                                            // сбрасываем флаг устройства после выполнения
            } else {                                                                                  // если в СМС не указано устройство, то
              gsm.SMSsend(F("Что выключить?"), SMSnum);                                               // отправляем об этом сообщение
            }                                                                                         // 
            flgFunc = 20;                                                                             // сбрасываем флаг действия после выполнения
            break;                                                                                    //
        }                                                                                             //
      } else {                                                                                        //
        gsm.SMSsend(F("Ошибка в тексте!"), SMSnum);                                                   // Если текст пришёл не верный, то отправляем об этом сообщение
      }                                                                                               //
    }                                                                                                 //
  }                                                                                                   //
}                                                                                                     //
Алгоритм работы скетча:
До кода void setup() определяются номера выводов, объявляются переменные и функции, подключаются библиотеки, и создаются объекты для работы с ними.
Перед загрузкой скетча не забудьте задать в переменной SMSnum номер телефона, куда будет приходить смс-уведомление о пройденной идентификации!
В коде void setup() конфигурируются выбранные выводы, инициируется работа GSM/GPRS Shield, выполняется цикл ожидания готовности GSM/GPRS Shield к работе (регистрация в сети оператора). И после выполнения всех указанных действий выполняется оповещение о готовности к работе, путем отправки смс на указанный номер.
Код void loop() выполняется только при получении смс сообщения. Сам блок разделён на две основные части: приём входящих сообщений и выполнение указанных в сообщении действий.
Приём входящих сообщений состоит из следующих действий:
- Считывание сообщения из памяти SIM-карты, после чего функция автоматически их оттуда удаляет.
- После считывания сообщения запускается цикл, в котором текст сообщения проверяется на наличие в нём управляющих команд;
- Если команда найдена, то внутри него запускается второй цикл, в котором текст так же проверяется, но уже на наличие в нём имени устройства;
- Если имя устройства найдено, то выполняется проверка на наличие дополнительного параметра, указанного с символом "%" - процент (от 0 до 100) яркости/скорости, с которым будет работать указанное устройство.
- Если дополнительный параметр был указан, то ставится флаг о его наличии в полученном смс.
Выполнение указанных в сообщении действий:
- После того, как все флаги были выставлены, происходит проверка наличия флага дополнительного параметра. Если он присутствует, тогда выполняется вычисление значения числа, указанного перед символом %:- Для этого мы находим количество символов в строке, расположенных слева от символа %;
- Полученное число покажет нам порядковый номер символа %в массивеstrSMStxt;
- Для того, чтобы узнать, какое значение было указано, проверим 3 ближайшие ячейки массива, расположенные слева от символа %:- Если 1 ячейка, расположенная ближе всего к символу %, содержит число от 0 до 9, то тогда мы заносим её значение в переменную Sum. Это будет разряд "единицы";
- После этого внутри первой проверки выполняется вторая проверка 2 ячейки на наличие числа от 0 до 9. Если число найдено, то оно умножается на 10 и прибавляется к переменной Sum. Это будет разряд "десятки";
- После этого внутри второй проверки производится третья проверка 3 ячейки. Если в ней найдена 1, то она умножается на 100 и прибавляется к переменной Sum. Это будет разряд "сотни".
- Если же в третьей проверке окажется, что в "сотнях" указано больше 1, то флаг flgPWMбудет сброшен;
 
- Если 1 ячейка, расположенная ближе всего к символу %, содержит число от 0 до 9, то тогда мы заносим её значение в переменную 
 
- Для этого мы находим количество символов в строке, расположенных слева от символа 
- Выполняется проверка наличия флага flgFunc:- Если флаг flgFuncбыл установлен, тогда выполняется проверка наличия флагаflgDev:- Если флаг flgDevбыл установлен, тогда выполняется проверка наличия флагаflgPWM:- Если флаг flgPWMустановлен, тогда выполняется подача ШИМ-сигнала на вывод с указанным в сообщении устройством и отправка смс с уведомлением об успешном выполнении;
- Если флаг flgPWMне установлен, тогда выполняется подача сигналаHIGHна вывод с указанным устройством и отправка смс с уведомлением об успешном выполнении;
 
- Если флаг 
- Если флаг flgDevне установлен, тогда производится отправка смс уведомления о том, что в сообщении не указано устройство;
 
- Если флаг 
- Если флаг flgFuncне установлен, тогда производится отправка смс уведомления о том, что пришло ошибочное сообщение.
 
- Если флаг 

Обсуждение