Идея создать розетку, управляемую через SMS, появилась у меня давно — еще в 2016 году. Однако, как это часто бывает, времени на реализацию проекта тогда не нашлось. Тем не менее, я не отказался от этой задумки и розетка, все-таки, была разработана реализована.
Этот проект казался мне отличной возможностью познакомиться с программно-аппаратной платформой arduino, а заодно создать полезное устройство, которое могло бы пригодиться в повседневной жизни. И вот, спустя несколько лет, я наконец решил воплотить эту идею в жизнь.
Если вы тоже давно откладывали интересный проект, возможно, сейчас самое время вернуться к нему и сделать что-то действительно полезное и увлекательное!
Реализация
Для реализации моей задумки я подготовил следующие компоненты:
- GSM-модуль SIM800L;
- контроллер Arduino Nano;
- настраиваемый преобразователь напряжения;
- релейный модуль.
Также в арсенале были дополнительные элементы: макетная плата, провода, набор резисторов и диоды.
О базовых вещах в Arduino, например, как зажигать диоды, рассказывать не буду — об этом уже написано множество статей и руководств. Наша главная задача — соединить GSM-модуль с Arduino и научиться корректно получать с него информацию, отправляя команды. Затем, используя данные из SMS, мы будем изменять состояние цифрового выхода, к которому подключено реле.
Схема подключения
На просторах интернета можно найти множество схем подключения Arduino к GSM-модулю SIM800L. Одна из таких схем представлена ниже.

Но, у меня в распоряжении не было ардуино уно, была только NANO. Поэтому моя схема выглядит вот так:

В первоначальной схеме GSM-модуль был подключен напрямую к Arduino. Однако позже я наткнулся на информацию, что SIM800L потребляет значительный ток, особенно при передаче данных или установке соединения. Это могло привести к перегрузке и даже повреждению Arduino.
Чтобы избежать риска, я решил пересмотреть схему и добавить дополнительные меры защиты. Например, можно использовать внешний источник питания для GSM-модуля или установить стабилизатор напряжения. Это не только обезопасит Arduino, но и обеспечит стабильную работу модуля.
При первых попытках я не сделал общую линию земли с ардуино, и схема была такая (но она не верна):

Если нет общей земли, в мониторе последовательного порта неверно отображаются символы, приходящие из GMS модуля.
Arduino в моем проекте питается от USB, а для GSM-модуля я использовал отдельный блок питания на 9 вольт. Чтобы обеспечить модулю правильное рабочее напряжение (от 3,3 до 4,4 вольта), я подключил его через настраиваемый преобразователь напряжения, который понизил напряжение до 4,1 вольта.
После запуска схемы статус модуля можно легко определить по мигающему красному диоду. Вот что означают разные режимы индикации:
- Мигание каждую секунду: модуль не подключен к сети.
- Мигание каждые 2 секунды: установлено активное соединение для передачи данных GPRS.
- Мигание каждые 3 секунды: модуль успешно подключился к сети.
Эта простая индикация помогает быстро понять, работает ли модуль корректно и готов ли он к приему команд.
Скетч для GSM-модуля
Скетч для тестового «общения» с GSM-модулем я нашел в интернете. Единственное, что я изменил, — это пины для UART-порта, через который Arduino взаимодействует с модулем. В оригинальном скетче использовались пины 2 и 3, но я заменил их на 5 и 6. Причина проста: пины 2 и 3 на моей Arduino были плохо пропаяны, а перепаивать их не хотелось.
Скетч приведен ниже:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(5, 6);
void setup()
{
Serial.begin(19200);
mySerial.begin(19200);
Serial.println("Initializing...");
delay(1000);
mySerial.println("AT");
updateSerial();
mySerial.println("AT+CSQ");
updateSerial();
mySerial.println("AT+CCID");
updateSerial();
mySerial.println("AT+CREG?");
updateSerial();
}
void loop()
{
updateSerial();
}
void updateSerial()
{
delay(500);
while (Serial.available())
{
mySerial.write(Serial.read());
}
while(mySerial.available())
{
Serial.write(mySerial.read());
}
}
В скетче, который я использовал, уже был заложен небольшой опрос модуля в блоке setup. Это позволило сразу проверить, корректно ли работает GSM-модуль после запуска.
В блоке loop реализовано простое перенаправление данных между портами. Если модуль отправляет какие-то данные, они перенаправляются в порт компьютера. Если же мы вводим команду, она отправляется в порт GSM-модуля.
После успешного соединения можно воспользоваться таблицей со списком команд, и поэкспериментировать, чтобы понять, как модуль реагирует на различные запросы. Это отличный способ разобраться в его работе и проверить функциональность.
На этом этап подключения и тестирования GSM-модуля можно считать завершенным. Теперь предстоит разобраться, как модуль получает SMS, как их можно прочитать и удалить.
Работа с СМС сообщениями
Нас интересуют команды для работы с СМС. По таблице находим, что при получении СМС модуль выдает сообщение:
+CMTI: «SM»,<номер смс>
В данном примере <номер смс>-это номер сообщения на sim-карте.
Это значит, что при получении этой строки, нужно «отрезать» цифру с номером сообщения. Далее послать модулю команду на получение СМС с этим номером:
AT+CMGR=<номер смс>
Для проверки команд отправим на sim-карту, вставленную в модуль, любую смс. Я выслал просто «1». Ждем некоторое время и видим в консоли, сообщение +CMTI: «SM»,1.
Теперь попробуем сделать вручную получение СМС по номеру, и посмотрим на ответ модуля. Отправляем AT+CMGR=1
Получаем ответ вида:
+CMGL: 5,”REC UNREAD”,”+7XXXXXXXXXX”,””,”22/11/10,20:33:16+40″
1
В первой строке отображается информация о сообщении (от кого, время, дата и т.д.), во второй строке само сообщение (она может быть полезна, если нужно отфильтровать номера, от которых воспринимать команды).
Наша задача- «выпилить» вторую строку ответа и сравнить её с некоторым значением, по которому мы хотим замыкать реле или размыкать. Далее послать сигнал на пин ардуино, к которому подключено реле.
Для того, чтобы «вырезать» вторую строку сообщения, нужно найти символ кавычек, далее перевод каретки (\r\n) и, начиная со следующего за ним символа, выбрать всё, до следующего переноса каретки. А после этого проделывать вышеописанные операции.
Функция для этого:
void get_SMS_text(String allText){
simbolPos = allText.lastIndexOf('"');
SMSText = allText.substring(simbolPos+1);
SMSText = SMSText.substring(SMSText.indexOf('\n') + 1);
SMSText = SMSText.substring(0, SMSText.indexOf('\r'));
}
Включаем диод через отправку СМС
Далее, просто сравниваем полученное сообщение с некоторым эталоном (например, 1 включить, 0 – выключить). И устанавливаем нужное значение на пине к которому будет подключено реле.
Функция:
void switch_pin(String SMSText){
if(SMSText == "1"){
digitalWrite(13, HIGH);
} else if(SMSText == "0") {
digitalWrite(13, LOW);
}
}
Для проверки, на пин, к которому будет подключено реле, я сначала подключил диод. Поэтому, для зажигания диода, на пине устанавливается значение HIGH, а для выключения LOW.
Схема после подключения диода:

После этого, посылаем команду удаления СМС, чтобы не забивать память. Но этого можно не делать, тогда у нас будет хранится история сообщений.
Проверка номера телефона
Так же, я написал функцию для проверки номера телефона, тогда схема будет работать при получении СМС от предопределенного номера(ов).
Функция проверки номера:
bool check_phone_number(String SMSText){
String phoneNumber = "";
simbolPos = SMSText.indexOf('+', 20);
phoneNumber = SMSText.substring(simbolPos+1, SMSText.indexOf('"', simbolPos));
return (phoneNumber == trustedNumber);
}
Для работы функции нужно объявить глобальную переменную trustedNumber типа String и записать в нее нужно номер.
Полученный скетч:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(5, 6); String incomingBytes;
String signalFromSIM;
String SMSNumber;
String SMSText;
int simbolPos;
String trustedNumber = "7**********";
void setup()
{
Serial.begin(19200);
mySerial.begin(19200);
Serial.println("Initializing...");
delay(1000);
mySerial.println("AT");
updateSerial();
mySerial.println("AT+CSQ");
updateSerial();
mySerial.println("AT+CCID");
updateSerial();
mySerial.println("AT+CREG?");
updateSerial();
mySerial.println("AT+CMGF=1");
updateSerial();
pinMode(13, OUTPUT);
}
void loop()
{
updateSerial();
}
void updateSerial()
{
incomingBytes = "";
while (Serial.available())
{
incomingBytes = Serial.readString();
if(incomingBytes.indexOf("AT") == -1){
incomingBytes += (char)26;
}
mySerial.println(incomingBytes);
}
while(mySerial.available())
{
signalFromSIM = mySerial.readString();
if(signalFromSIM.indexOf("CMGR") != -1){
if(check_phone_number(signalFromSIM)){
get_SMS_text(signalFromSIM);
switch_pin(SMSText);
send_command("AT+CMGDA=\"DEL ALL\"");
}
}else if(signalFromSIM.indexOf("CMTI") != -1){
get_sms_number(signalFromSIM);
send_command("AT+CMGR=" + SMSNumber);
} else{
Serial.println(signalFromSIM);
}
}
}
void get_sms_number(String message){
simbolPos = signalFromSIM.lastIndexOf(',');
SMSNumber = signalFromSIM.substring(simbolPos+1);
}
void send_command(String command){
mySerial.println(command);
}
void get_SMS_text(String allText){
simbolPos = allText.lastIndexOf('"');
SMSText = allText.substring(simbolPos+1);
SMSText = SMSText.substring(SMSText.indexOf('\n') + 1);
SMSText = SMSText.substring(0, SMSText.indexOf('\r'));
}
void switch_pin(String SMSText){
if(SMSText == "1"){
digitalWrite(13, HIGH);
} else if(SMSText == "0") {
digitalWrite(13, LOW);
}
}
bool check_phone_number(String SMSText){
String phoneNumber = "";
simbolPos = SMSText.indexOf('+', 20);
phoneNumber = SMSText.substring(simbolPos+1, SMSText.indexOf('"', simbolPos));
return (phoneNumber == trustedNumber);
}
Тестовый стенд

После запуска, отправляем на номер сим карты, установленной в GSM-модуле, смс с текстом «1». Ждем какое-то время и видим, что диод загорелся. После этого посылаем «0» – диод тухнет.
Теперь следующий этап. Чтобы управлять реле, и по СМС «1» подключать розетку, а по «0»- отключать, нужно изменить сигналы выдаваемы на пин управления. Т.к. реле замыкается, когда на пине LOW и размыкается когда HIGH. Так же в области «setup» нужно сразу выставить уровень сигнала на пине, к которому подключено реле, в значение HIGH, чтобы реле было изначально разомкнуто.
Полученный скетч:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(5, 6); String incomingBytes;
String signalFromSIM;
String SMSNumber;
String SMSText;
int simbolPos;
String trustedNumber = "7**********";
void setup()
{
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
Serial.begin(19200);
mySerial.begin(19200);
Serial.println("Initializing...");
delay(1000);
mySerial.println("AT");
updateSerial();
mySerial.println("AT+CSQ");
updateSerial();
mySerial.println("AT+CCID");
updateSerial();
mySerial.println("AT+CREG?");
updateSerial();
mySerial.println("AT+CMGF=1");
updateSerial();
}
void loop()
{
updateSerial();
}
void updateSerial()
{
incomingBytes = "";
while (Serial.available())
{
incomingBytes = Serial.readString();
if(incomingBytes.indexOf("AT") == -1){
incomingBytes += (char)26;
}
mySerial.println(incomingBytes);
}
while(mySerial.available())
{
signalFromSIM = mySerial.readString();
if(signalFromSIM.indexOf("CMGR") != -1){
if(check_phone_number(signalFromSIM)){
get_SMS_text(signalFromSIM);
switch_pin(SMSText);
send_command("AT+CMGDA=\"DEL ALL\"");
}
}else if(signalFromSIM.indexOf("CMTI") != -1){
get_sms_number(signalFromSIM);
send_command("AT+CMGR=" + SMSNumber);
} else{
Serial.println(signalFromSIM);
}
}
}
void get_sms_number(String message){
simbolPos = signalFromSIM.lastIndexOf(',');
SMSNumber = signalFromSIM.substring(simbolPos+1);
}
void send_command(String command){
mySerial.println(command);
}
void get_SMS_text(String allText){
simbolPos = allText.lastIndexOf('"');
SMSText = allText.substring(simbolPos+1);
SMSText = SMSText.substring(SMSText.indexOf('\n') + 1);
SMSText = SMSText.substring(0, SMSText.indexOf('\r'));
}
void switch_pin(String SMSText){
if(SMSText == "1"){
digitalWrite(13, LOW);
} else if(SMSText == "0") {
digitalWrite(13, HIGH);
}
}
bool check_phone_number(String SMSText){
String phoneNumber = "";
simbolPos = SMSText.indexOf('+', 20);
phoneNumber = SMSText.substring(simbolPos+1, SMSText.indexOf('"', simbolPos));
return (phoneNumber == trustedNumber);
}
После этого основная часть готова.
Схема с лампой и реле:

Тестовый стенд для проверки управления реле.

Некоторые выводы.
Чтобы из этого всего получилось полноценное устройство – нужно вместить всё в небольшой корпус. Реле будет замыкать провод, подведенный к розетке. Так же скетч нужно дополнить командой, в ответ на которую, будет выслана СМС о том, в каком положении сейчас находится реле (вкл/выкл). Arduino Nano планирую заменить на Arduino Pro Mini, это позволит питать плату и GSM-модуль от одной понижающей платы. Напряжение питания у Arduino Pro Mini `3,3 вольта, как и у GSM-модуля (у Nano 5 вольт). Либо использовать Arduino ATtiny85. ввиду маленького размера и наименьшей избыточности.
Так же, хотелось бы, чтобы данным устройством можно было управлять через интернет. Но для того, чтобы можно было отправить на устройство команду – нужен промежуточный сервер, куда можно подключиться с устройства управления (телефон/компьютер) и чтобы к нему была подключена «GSM-розетка». Но это уже из области умного дома, что, возможно, буду делать в будущем. Далее, хочу сделать вторую часть данного проекта (либо дополню эту) где постараюсь все уместить в корпус и сделать функцию получения состояния реле. На данный момент нет нужных деталей, но они в пути.
Статьи по проекту
2 комментария к “Умная розетка. Часть 1 – Тесты.”