[sape_tizer]
Ср. Май 31st, 2023

Что и как строить на земельном участке или обо всем понемногу

Все о инструментах, строительстве, работах, АРДУИНО, электрика, электроника и многое другое

SIM800L и Ардуино, MQTT через GSM (удаленное управление автомобилем)

GSM to MQTT

Добрый день всем посетителям сайта.

После довольно долгого перерыва (год с немногим) и дикого количества проблем руки все таки дошли до сайта. И причина- товарищ по работе попросил сделать устройство для запуска/ останова машины (сокращенно ЗОМ- Запуск/ Останов Машины) через MQTT. Я сказал что сделать то можно и взялся за это дело. Тем более что все детали он предоставил. Так как не хотелось лезть в проводку да и обойтись малой кровью то решили использовать резервный пульт автомобиля. Для управления подпаяли по паре проводков к каждой кнопке (их всего 3 в пульте) и их подсоединили к нормально разомкнутым контактам 3 реле. Теперь при поступлении сигнала они будут работать в порядке прописанном в скетче. Для полной сборки устройства нужно:

  1. Ардуино УНО (вообще любая платформа)
  2. Модуль GSM SIM800L
  3. Блок реле на 4 шт
  4. Резервный пульт управления автомобилем
  5. БП с Али чтобы понизить напряжение с бортовой сети до нужного (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
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 ответы в мониторе порта
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.

Добавить комментарий