SIM800L и Ардуино, MQTT через GSM (удаленное управление автомобилем)
Добрый день всем посетителям сайта.
После довольно долгого перерыва (год с немногим) и дикого количества проблем руки все таки дошли до сайта. И причина- товарищ по работе попросил сделать устройство для запуска/ останова машины (сокращенно ЗОМ- Запуск/ Останов Машины) через MQTT. Я сказал что сделать то можно и взялся за это дело. Тем более что все детали он предоставил. Так как не хотелось лезть в проводку да и обойтись малой кровью то решили использовать резервный пульт автомобиля. Для управления подпаяли по паре проводков к каждой кнопке (их всего 3 в пульте) и их подсоединили к нормально разомкнутым контактам 3 реле. Теперь при поступлении сигнала они будут работать в порядке прописанном в скетче. Для полной сборки устройства нужно:
Ардуино УНО (вообще любая платформа)
Модуль GSM SIM800L
Блок реле на 4 шт
Резервный пульт управления автомобилем
БП с Али чтобы понизить напряжение с бортовой сети до нужного (2 шт)
Подробнее о деталях. Модуль GSM может также быть совершенно любым, нужно будет прописать какой модуль есть у вас. Опять же если у вас SIM800L то они бывают красные и синие. У меня был дешевый красный. Для его подключения нужно будет использовать резистивный делитель с парой резисторов по 10кОм чтобы снизить прием на SIM800L до требуемых 2,5 В. Опять же он неудобен в плане подключения по питанию. У него какое то косое напряжение в 4,2 В. Приходится запитывать его от другого БП. Но об этом немного ниже. Синий блок SIM800L от всего этого уже избавлен (как говорят, у меня его не было поэтому не могу утверждать). Просто включаете напрямую и вуаля- все работает.
Блок реле- берете по количеству кнопок в вашем пульте, или чуть больше. Например в данном случае пульт с 3 кнопками а блок реле с 4 реле. Нет блоков на 3 реле и по 1 реле ставить муторно.
Переходим непосредственно к кодингу. Первое что было написано- алгоритм запуска машины с сработкой блока реле. Т.е. полная имитация работы пульта. У каждого автомобиля это, вероятно, разный алгоритм но описать его довольно просто. Например мой случай:
int dOut1 = 8;
int dOut2 = 9;
int dOut3 = 10;
String sRead;
int Active = 0;
int Unactive = 1;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(dOut1, OUTPUT);
pinMode(dOut2, OUTPUT);
pinMode(dOut3, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
sRead = "0";
if (Serial.available())
{
sRead = Serial.parseInt();
Serial.println(sRead);
}
digitalWrite(dOut1, Unactive);
digitalWrite(dOut2, Unactive);
digitalWrite(dOut3, Unactive);
// запуск
if (sRead == "1")
{
digitalWrite(dOut1, Active);
delay(1200);
digitalWrite(dOut1, Unactive);
delay(500);
digitalWrite(dOut3, Active);
delay(500);
digitalWrite(dOut3, Unactive);
}
// остановка
if (sRead == "2")
{
digitalWrite(dOut1, Active);
delay(1200);
digitalWrite(dOut1, Unactive);
delay(500);
digitalWrite(dOut2, Active);
delay(500);
digitalWrite(dOut2, Unactive);
}
//закрыть
if (sRead == "3")
{
digitalWrite(dOut1, Active);
delay(500);
digitalWrite(dOut1, Unactive);
}
//открыть
if (sRead == "4")
{
digitalWrite(dOut2, Active);
delay(500);
digitalWrite(dOut2, Unactive);
}
//поиск
if (sRead == "5")
{
digitalWrite(dOut3, Active);
delay(500);
digitalWrite(dOut3, Unactive);
}
}
Здесь все довольно просто- разные комбинации нажатия кнопок приводят к нужному срабатыванию реле. Входы релейного блока подключаются к выводам 8, 9, 10 Ардуино. Запускаете в Arduino IDE монитор порта, вводите в верхнее поле значение от 1 до 5 и реле будут отрабатывать требуемую последовательность. Таким образом первая часть кодинга УЖЕ написана. Кстати по переменным. dOut1, dOut2, dOut3- пины выходных портов, String sRead- значение, что будем получать из монитора порта (в дальнейшем эта переменная так и останется), int Active = 0; int Unactive = 1; — эти две переменные задают активный и пассивный уровни срабатывания реле. Есть реле где для включения нужна логическая 1 а для отключения- 0. В моем же случае логика инверсная, т.е. для включения нужен логический 0 а для отключения- 1. Если у вас описанный выше блок- просто поменяйте местами 0 и 1 в данных переменных. Иначе бегать по коду и менять 0 на 1 и обратно…. так не пишутся программы.
Теперь перейдем непосредственно к написанию полностью программы. Как оказалось найти нормальный пример- это что то ненормальное. Буквально все найденные приведенные примеры отказывались соединяться с MQTT сервером. От слова абсолютно. На поиски нужной библиотеки было потрачено около 3 дней. Перепробовано десятки скетчей и пробовал переписать свой скетч под курятник… Беда в том что большинство приложений для умного дома работают с WiFi сетью и, казалось бы, авторизация на MQTT такая же но… не такая. Но кто ищет тот всегда найдет и я нашел на каком то импортном сайте ответ на свою проблему. Посоветовали поставить библиотеку FONA. Правда при установке этой библиотеки пришлось установить еще 3 библиотеки и вам тоже придется их поставить.
Fona
Взял из нее пример с подключением MQTT.
#include <Adafruit_SleepyDog.h>
#include <SoftwareSerial.h>
#include "Adafruit_FONA.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_FONA.h"
/*************************** FONA Pins ***********************************/
// Default pins for Feather 32u4 FONA
#define FONA_RX 9
#define FONA_TX 8
#define FONA_RST 4
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
/************************* WiFi Access Point *********************************/
// Optionally configure a GPRS APN, username, and password.
// You might need to do this to access your network's GPRS/data
// network. Contact your provider for the exact APN, username,
// and password values. Username and password are optional and
// can be removed, but APN is required.
#define FONA_APN ""
#define FONA_USERNAME ""
#define FONA_PASSWORD ""
/************************* Adafruit.io Setup *********************************/
#define AIO_SERVER "io.adafruit.com"
#define AIO_SERVERPORT 1883
#define AIO_USERNAME "...your AIO username (see https://accounts.adafruit.com)..."
#define AIO_KEY "...your AIO key..."
/************ Global State (you don't need to change this!) ******************/
// Setup the FONA MQTT class by passing in the FONA class and MQTT server and login details.
Adafruit_MQTT_FONA mqtt(&fona, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
// You don't need to change anything below this line!
#define halt(s) { Serial.println(F( s )); while(1); }
// FONAconnect is a helper function that sets up the FONA and connects to
// the GPRS network. See the fonahelper.cpp tab above for the source!
boolean FONAconnect(const __FlashStringHelper *apn, const __FlashStringHelper *username, const __FlashStringHelper *password);
/****************************** Feeds ***************************************/
// Setup a feed called 'photocell' for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
Adafruit_MQTT_Publish photocell = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/photocell");
// Setup a feed called 'onoff' for subscribing to changes.
Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/onoff");
/*************************** Sketch Code ************************************/
// How many transmission failures in a row we're willing to be ok with before reset
uint8_t txfailures = 0;
#define MAXTXFAILURES 3
void setup() {
while (!Serial);
// Watchdog is optional!
//Watchdog.enable(8000);
Serial.begin(115200);
Serial.println(F("Adafruit FONA MQTT demo"));
mqtt.subscribe(&onoffbutton);
Watchdog.reset();
delay(5000); // wait a few seconds to stabilize connection
Watchdog.reset();
// Initialise the FONA module
while (! FONAconnect(F(FONA_APN), F(FONA_USERNAME), F(FONA_PASSWORD))) {
Serial.println("Retrying FONA");
}
Serial.println(F("Connected to Cellular!"));
Watchdog.reset();
delay(5000); // wait a few seconds to stabilize connection
Watchdog.reset();
}
uint32_t x=0;
void loop() {
// Make sure to reset watchdog every loop iteration!
Watchdog.reset();
// Ensure the connection to the MQTT server is alive (this will make the first
// connection and automatically reconnect when disconnected). See the MQTT_connect
// function definition further below.
MQTT_connect();
Watchdog.reset();
// Now we can publish stuff!
Serial.print(F("\nSending photocell val "));
Serial.print(x);
Serial.print("...");
if (! photocell.publish(x++)) {
Serial.println(F("Failed"));
txfailures++;
} else {
Serial.println(F("OK!"));
txfailures = 0;
}
Watchdog.reset();
// this is our 'wait for incoming subscription packets' busy subloop
Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(5000))) {
if (subscription == &onoffbutton) {
Serial.print(F("Got: "));
Serial.println((char *)onoffbutton.lastread);
}
}
// ping the server to keep the mqtt connection alive, only needed if we're not publishing
//if(! mqtt.ping()) {
// Serial.println(F("MQTT Ping failed."));
//}
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
int8_t ret;
// Stop if already connected.
if (mqtt.connected()) {
return;
}
Serial.print("Connecting to MQTT... ");
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
Serial.println(mqtt.connectErrorString(ret));
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000); // wait 5 seconds
}
Serial.println("MQTT Connected!");
}
В скетче неправильно расставлены знаки из за некорректного переноса скетча. Обратите внимание. Возьмите пример из самой Arduino IDE.
Ввел данные по моему MQTT серверу (использовал srv2.clusterfly.ru из примера выше). Вроде пишет в мониторе порта что все нормально- соединение с MQTT установлено! Ввел данные по cloudmqtt, там очень удобная панель управления хоть и стал он теперь платный (жаль, очень жаль) и вижу- действительно подключено еще 1 устройство! Вообще класс! Значит все таки устройство то заработало через GSM! Опять ввел srv2.clusterfly.ru и занялся отладкой. Было потрачено еще 2 вечера на поиск в интернете, потом я плюнул на все и решил разобраться сам в данной библиотеке, и, вот наконец то, додумал что же там такое наворочено. Как оказалось что это все таки пример и данный пример как отправляет так и получает данные на сервер что, согласитесь, вообще классно! Но проблема в том что он отправляет и сам получает данные именно те что сам же и послал. И поэтому реле у меня щелкали вообще в беспорядке и непонятно от чего. Опять же по монитору порта смотришь…. такая портянка данных с АТ командами, ответами SIM800L и самого контроллера что нужный блок приходилось копировать в блокнот и там уже искать…
MQQT ответы в мониторе порта
Но это все решилось не совсем быстро конечно. В итоге все таки получилось запустить ЗОМ. Дальнейшая отладка заключалась в настройке задержки срабатывания реле после поступления сигнала. Вроде все просто: пришел сигнал- работа, но опять же нет. После поступления сигнала проходило до 40 секунд прежде чем начинали срабатывать реле. Согласитесь- это очень много! Вобщем решил таки и эту проблему! Теперь между нажатием кнопки управления на телефоне и запуском проходит где то 3 секунды! Пока все это исправлял придумал такую вещь- при нажатии кнопки на телефоне, пока не отработает сигнал на реле, кнопка остается активной. Как реле отработало- кнопка опять становится неактивной. Это как бы подтверждает успешность запуска, в противном случае кнопка останется активной что указывает что запуск не произошел. Вроде мелочь но нужная.
Настройки кнопок на телефоне будут выглядеть так:
Настройка клиента на телефоне
Размытая часть- ваше имя пользователя. Значения кнопок при запуске- 1, остановке-2, открытии- 3, закрытии-4, поиске автомобиля- 5. Выключение для ВСЕХ кнопок- 0. Можете указать для каждой кнопки свое значение отключения. В моем же случае если вы нажали сразу несколько кнопок то пройдет срабатывание только по первой нажатой кнопке, затем ВСЕ кнопки сразу станут неактивными.
Теперь перейдем к достоинствам данного плагина. Во- первых он идеально подходит к srv2.clusterfly.ru т.к. сама библиотека приписывает к названию топика впереди имя пользователя что для srv2.clusterfly.ru является обязательным. Вам уже не надо думать что вы написали или нет. Еще в названии топиков должно присутствовать слово «/feed/». Обязательно или нет- незнаю, но так написано- Notice MQTT paths for AIO follow the form: username»/feeds/feedname», т.е., в нашем случае, AIO_USERNAME»/feeds/auto/». Ничего сложного в принципе нет. Во- вторых- ничего мудрить с описанием подключения уже ненадо, ввел данные и готово. Пиши обработчик. В- третьих- размер. Мой скетч занял «всего» 14,8 кБ. Остальные программы которые я попробовал уходили далеко за 20 кБ.
Недостаток по моему только один- очень большой объем данных при отладке в мониторе порта. Если бы была возможность выборочного отключения отображаемых данных то была бы самая лучшая библиотека!
Теперь поговорим собственно о самой схемотехнике построения данного устройства. Как и говорилось выше что я использовал SIM800L. Все GSM модули в режиме передачи потребляют дикие токи, вплоть до 2 А. Поэтому их не рекомендуют запитывать от Ардуино. Я запитал и, в принципе, ничего. Работает. Могу предложить следующий вариант, правда, незнаю, будет ли он работать или нет. Подключаем SIM800L от Ардуино через диод и электролитический конденсатор от 1000 мкф и выше. Их можно взять с материнских плат компьютеров. Там есть и по 2200 мкф и выше. Смысл в том что 2А SIM800L потребляет не постоянно а на пике и очень быстро. Поэтому 1000 мкф очень сгладит такое потребление а диод во- первых не даст пройти данному падению в саму плату Ардуино, а во-вторых на диоде немного упадет напряжение ~0,2-0,4В что уже будет гораздо ближе к заявленным 4,2В-4,6В. Прием на SIM800L, вывод RX, обязательно включаем через резиситивный делитель 10к/10к. Один конец делителя пойдет к выводу Ардуино, другой конец на GND а средняя точка непосредственно к RX SIM800L. Следующее- подключаем реле тоже к 5В Ардуино. Т.к. реле не работают в паре никогда то и тока хватает. Дальше можем подключить и сам пульт управления авто на 3В шину питания. Правда я еще не пробовал но.. думаю потянет. Скачать архив можете Прошивка ЗОМ. Выкладываю прошивку т.к. замотался править все эти кавычки и скобочки. Ну не переносит текст правильно WP и все тут. Даже с подключенным SyntaxHighlighter Evolved.
А теперь непосредственно про питание всех устройств. SIM800L, как и сказано выше, кушает очень даже неплохо. Поэтому в автомобиль можно поставить БП с 12 В на 5В, или взять любой китайский регулируемый и настроить как надо. На выход опять же желательно поставить большую емкость и даже через индуктивность дабы срезать помехи от бортовой сети автомобиля. Такую же историю можно сделать и с платой Ардуино но питание можно «уронить» до 9В и подключиться непосредственно к адаптеру питания. Опять же емкости и индуктивности только приветствуются. Выводы GND у Ардуино и GSM модуля должны быть соединены. Обязательно! Выводы для подключения модулей:
GSM
Arduino
RX (через делитель 10к/10к)
3
TX
2
Думаю что вы все поняли. Что непонятно- пишите в комментариях. Данный принцип можно использовать для контроля и управления удаленных объектов где нет сетей WiFi но есть GSM.
2 комментария для “SIM800L и Ардуино, MQTT через GSM (удаленное управление автомобилем)”
Здравствуйте, прошивка не скачивается.
Все отлично скачивается. только что проверил.