Добрый день всем посетителям сайта.
После довольно долгого перерыва (год с немногим) и дикого количества проблем руки все таки дошли до сайта. И причина- товарищ по работе попросил сделать устройство для запуска/ останова машины (сокращенно ЗОМ- Запуск/ Останов Машины) через 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 библиотеки и вам тоже придется их поставить.
Взял из нее пример с подключением 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 и самого контроллера что нужный блок приходилось копировать в блокнот и там уже искать…
Но это все решилось не совсем быстро конечно. В итоге все таки получилось запустить ЗОМ. Дальнейшая отладка заключалась в настройке задержки срабатывания реле после поступления сигнала. Вроде все просто: пришел сигнал- работа, но опять же нет. После поступления сигнала проходило до 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.
Здравствуйте, прошивка не скачивается.
Все отлично скачивается. только что проверил.