GSM-система контроля за автоматическим поливом
- Войдите на сайт для отправки комментариев
Вс, 19/06/2016 - 02:52
Доброго всем времени суток.
Хотел бы поделится со всеми одной своей разработкой. Может данная информация окажется кому-то полезной.
На своей даче я реализовал автоматическую систему полива. Реализована она на готовых электроных таймерах. Один таймер включает насос типа "малыш", погруженный в колодец. Вода поступает в бочку. Бочка - 200 литров. Набор воды обычно происходит через день с 21:00 до 21:20. Другой таймер открывает соленойдный клапан, и подогретая окружающей средой вода поступает в систему капельного полива. Открытие клапана происходит ежедневно с 15:00 до 20:30. И все бы хорошо, но система питается от 220VAC. Бывают отключения электричества. Может засориться магистральный фильтр. И пр... Одним словом, необходимо отслеживать изменения уровня воды в бочке. Было принято решение разработать устройство. Вот оно:
Устройство состоит из четырех модулей:
- Arduino Nano;
- GSM-модуль SIM800L;
- блок питания 220VAC/5VDC;
- понижающий DC-регулятор.
Выходное напряжение DC-регулятора установлено на уровне 4.18 вольт. От него запитывается SIM800L. При этом уровне напряжения SIM (по АТ запросу) выдает заряд аккумулятора около 100%. Вообще, от этого регулятора SIM работает очень стабильно.
Arduino и SIM в любой момент могут быть извлечены из устройства (просто, для удобства)
Хотелось бы отметить, что у Arduino Nano есть один несомненно большой плюс. Это наличие готового USB разъема. Нет необходимоти тащить ноут на дачу. Программу можно корректировать с телефона через ArduinoDroid. Можно отследить ход выполнения программы через Serial (опять же с телефона).
На первых трех аналоговых входах реализован кондуктометрический датчик. К ним и к GND подключаются электроды на разных уровнях в бочке. GND является общим электродом и подключается на самое дно бочки. Электроды на входах А0, А1 и А2 подключаются на нижнем, среднем и верхнем уровнях бочки соответственно. Как всем нам известно, значения на аналоговых входах может меняться от 0 до 1024. Значение более 1020 означает, что данный уровень водой не достигнут. Пороговое значение, при котором уровень считается достигнутым в программе установлен равным 800 (исходя из экспериментов проведенных в ванной). После установки устройства на месте, пороговое значение будет скорректированно для каждого уровня.
И так... Каков функционал данного устройства... При изменении уровня в бочке, оно звонит "хозяину". При этом мы не знаем, увеличился уровень или уменьшился. Да, конечно, можно было бы просто послать SMS-ку, и указать в ней что да как... Но исходящие SMS платны. Я не жадный, но дело принципа. Дача находится в 30-ти километрах от дома. Но это уже другой регион. Соответственно, роуминг. На этом наши сотовые операторы незаслуженно (я так считаю) наживаются. Поэтому, вместо того, чтоб слать SMS-ки, устройство нам будет звонить, а мы будем этот звонок игнорировать. Мы лучше сами позвоним на устройство, переключимся на телефоне на DTMF-приемник и в тоновом режиме примем текущие значения уровней в бочке:
Судя по картинке, бочка пуста (полив прошел успешно).
Симку нужно покупать с посекундным тарифом без каких либо ежемесячных платежей. Тогда ваши расходы на нее будут составлять 0.00 руб в месяц.
Данный способ передачи информации может быть использован и для других целей (показания датчиков и пр.). Так же в тоновом режиме можно удаленно управлять устройствами с телефона.
А так выглядит Serial Monitor, если устройство функционирует нормально:
А вот и программа:
#include <SoftwareSerial.h> SoftwareSerial mySerial(2, 3); // RX, TX int ch = 0; String val = ""; //переменная для приема данных от GSM-модуля int level_1=0; //переменная 1-го уровня int level_2=0; //переменная 2-го уровня int level_3=0; //переменная 3-го уровня int level_11=0; //промежуточная переменная 1-го уровня int level_22=0; //промежуточная переменная 2-го уровня int level_33=0; //промежуточная переменная 3-го уровня String Level="AT+VTS="; //переменная формирования АТ команд для передачи в GSM-модуль String L_1=""; String L_2=""; String L_3=""; unsigned long time; unsigned long time1=0; void setup() { digitalWrite(A0, 1); //включаем подтягивающий резистор аналогового входа А0 (уровень 1) digitalWrite(A1, 1); //включаем подтягивающий резистор аналогового входа А1 (уровень 2) digitalWrite(A2, 1); //включаем подтягивающий резистор аналогового входа А2 (уровень 3) if(analogRead(A0)>800) level_1=level_11=0; else level_1=level_11=1; //устанавливаем порог для уровня 1 раным 800 if(analogRead(A1)>800) level_2=level_22=0; else level_2=level_22=1; //устанавливаем порог для уровня 2 раным 800 if(analogRead(A2)>800) level_3=level_33=0; else level_3=level_33=1; //устанавливаем порог для уровня 3 раным 800 delay(20000); //время на инициализацию модуля Serial.begin(19200); //открываем COM-порт mySerial.begin(19200); //открываем порт GSM-модуля mySerial.println("AT+CLIP=1"); //включаем АОН delay(100); mySerial.println("AT+VTD=4"); //устанавливаем длительность в тоновом режиме равной 0,4сек delay(100); mySerial.println("ATD+79ХХХХХХХХХ;"); //звоним на свой номер delay(16000); mySerial.println("ATH0"); //разрываем связь через 16 сек delay(100); } void loop() { L_1=String(analogRead(A0)); //переводим "цифру" в String L_2=String(analogRead(A1)); //переводим "цифру" в String L_3=String(analogRead(A2)); //переводим "цифру" в String if (mySerial.available()) { //если GSM модуль что-то послал нам, while (mySerial.available()) { //сохраняем входную строку в переменную val ch = mySerial.read(); val += char(ch); delay(10); } if (val.indexOf("RING") > -1) { //если звонок обнаружен, то проверяем номер if (val.indexOf("79ХХХХХХХХХ") > -1) { //если номер звонящего наш Serial.println("--- MASTER RING DETECTED ---"); digitalWrite(13, HIGH); //включаем светодиод mySerial.println("ATA"); //устанавливаем соединение delay(1000); //задержка для включения DTMF-ресивера на телефоне mySerialLevel(); //отправляем значения уровней на DTMF-ресивер mySerial.println("ATH0"); //разрываем связь digitalWrite(13, LOW); //выключаем светодиод } } else Serial.println(val); //печатаем в монитор порта пришедшую строку val = ""; //обнуляем переменную val } time = millis(); if((time-time1)>=5000){ //раз в 5 секунд выводим значения уровней на монитор Serial.print(L_1); //выводим на монитор значение уровня 1 Serial.print("\t"); //табуляция Serial.print(L_2); //выводим на монитор значение уровня 2 Serial.print("\t"); //табуляция Serial.print(L_3); //выводим на монитор значение уровня 3 Serial.print("\t"); //табуляция SerialLevel(); //выводим на монитор сформированную АТ команду //Serial.print(time); //выводим на монитор значение времени Serial.println(""); //перенос строки time1=time; } CheckLevel(); //проверяем значения уровеней //в случае изменения звоним на свой номер } /***функция формирования AT+VTS команды для отслеживания в Serial ***/ void SerialLevel(){ Level+=char(34); Level+=L_1[0]; Level+=','; Level+=L_1[1]; Level+=','; if(L_1[2]>47&&L_1[2]<58) { Level+=L_1[2]; Level+=','; } if(L_1[3]>47&&L_1[3]<58) { Level+=L_1[3]; Level+=','; } Level+='#'; Level+=','; Level+=L_2[0]; Level+=','; Level+=L_2[1]; Level+=','; if(L_2[2]>47&&L_2[2]<58) { Level+=L_2[2]; Level+=','; } if(L_2[3]>47&&L_2[3]<58) { Level+=L_2[3]; Level+=','; } Level+='#'; Level+=','; Level+=L_3[0]; Level+=','; Level+=L_3[1]; if(L_3[2]>47&&L_3[2]<58) { Level+=','; Level+=L_3[2]; } if(L_3[3]>47&&L_3[3]<58) { Level+=','; Level+=L_3[3]; } Level+=char(34); Serial.print(Level); Level="AT+VTS="; } /***функция формирования AT+VTS команды для GSM-модуля ***/ void mySerialLevel(){ Level+=char(34); Level+=L_1[0]; Level+=','; Level+=L_1[1]; Level+=','; if(L_1[2]>47&&L_1[2]<58) { Level+=L_1[2]; Level+=','; } if(L_1[3]>47&&L_1[3]<58) { Level+=L_1[3]; Level+=','; } Level+='#'; Level+=','; Level+=L_2[0]; Level+=','; Level+=L_2[1]; Level+=','; if(L_2[2]>47&&L_2[2]<58) { Level+=L_2[2]; Level+=','; } if(L_2[3]>47&&L_2[3]<58) { Level+=L_2[3]; Level+=','; } Level+='#'; Level+=','; Level+=L_3[0]; Level+=','; Level+=L_3[1]; if(L_3[2]>47&&L_3[2]<58) { Level+=','; Level+=L_3[2]; } if(L_3[3]>47&&L_3[3]<58) { Level+=','; Level+=L_3[3]; } Level+=char(34); mySerial.println(Level); delay(15000); //while (1) {if(mySerial.available())break;}; Level="AT+VTS="; } /*** функция проверки изменения уровней ***/ void CheckLevel(){ if(analogRead(A0)>800) level_1=0; else level_1=1; //проверяем изменение уровня 1 if(analogRead(A1)>800) level_2=0; else level_2=1; //проверяем изменение уровня 2 if(analogRead(A2)>800) level_3=0; else level_3=1; //проверяем изменение уровня 3 if(level_1!=level_11||level_2!=level_22||level_3!=level_33){ // если один из уровней изменился mySerial.println("ATD+79ХХХХХХХХХ;"); //звоним на свой номер delay(16000); mySerial.println("ATH0"); //разрываем связь через 16 сек delay(60000); //делаем задержку на "дребезг зеркала воды" level_11=level_1; //запоминаем текущее значение уровня 1 в промежуточной переменной level_22=level_2; //запоминаем текущее значение уровня 2 в промежуточной переменной level_33=level_3; //запоминаем текущее значение уровня 3 в промежуточной переменной }; }Устройство так же делает звонок "хозяину" при каждой перезагрузке, что позволяет отследить были ли отключения электричества.
нельзя просто так сунуть выводы проца без защиты в бак или в грунт.. статика и другого рода наводки напряжения выведут из строя проц.. рано или поздно это случится.
можно более подробнее прокоментировать часть /***функция формирования AT+VTS команды для отслеживания в Serial ***/ ?
что куда формирует? тоновые сигналы в линию? какого итогового формата?
тоесть должна быть еще вторая часть которая эти сигналы принимает?
дешевая замена гпрс канала, очень здравая мысль.
нельзя просто так сунуть выводы проца без защиты в бак или в грунт.. статика и другого рода наводки напряжения выведут из строя проц.. рано или поздно это случится.
Можно. На используемых аналоговых входах подключены внутренние подтягивающие резисторы (программно). В результате получается замечательный делитель напряжения от внутреннего резистора к плюсу и от внешнего резистора (воды) к GND.
Данная функция всего лишь отображает в Serial подготовленную АТ команду. В проге есть другая функция, точно такая же, которая в нужный момент отправляет АТ команду в SIM800L через mySerial.
нельзя просто так сунуть выводы проца без защиты в бак или в грунт.. статика и другого рода наводки напряжения выведут из строя проц.. рано или поздно это случится.
Можно. На используемых аналоговых входах подключены внутренние подтягивающие резисторы (программно). В результате получается замечательный делитель напряжения от внутреннего резистора к плюсу и от внешнего резистора (воды) к GND.
Это как раз и является тем, что я назвал кондуктометрическим датчиком.
нельзя просто так сунуть выводы проца без защиты в бак или в грунт.. статика и другого рода наводки напряжения выведут из строя проц.. рано или поздно это случится.
Можно. На используемых аналоговых входах подключены внутренние подтягивающие резисторы (программно). В результате получается замечательный делитель напряжения от внутреннего резистора к плюсу и от внешнего резистора (воды) к GND.
ок, спорить не стану, достаточно почитать опыт других "экпериментаторов" которые пожгли входы таким подключением. там нужно ставить: два диода, токоограничивающий резистор, внешнюю подтяжку, это как минимум, ИМХО.
идея с передачей инфы на другую сторону неплаха, очень неплоха.
Да, я тоже так считаю. Именно альтернативным способом передачи данных и управления хотелось со всеми поделиться. А насчет делителя напряжения на внутреннем резисторе... Я не первый раз использую этот вариант. Пока (тьфу, тьфу) ни один вход и ни один проц не сгорел. Надеюсь, и не случится. Если вдруг..., сразу отпишусь и сам буду использовать что-то другое.
Блиныч, сейчас понял, что не так обозвал тему. Очень странно, что я, как человек открывший тему, не могу поменять ее название. С модераторами здесь на форуме, как я понял, проблема. Придется спамить и открыть еще одну тему с той же инфой, но сдругим названием. Мне очень важно мнение людей уже имевших опыт передачи данных в тоновом режиме. Так как некоторые проблемы в передаче данных все же существуют. Тему, пожалуй, назову: "SIM800L, передача данных в тоновом режиме". Short Circuit, присоединяйся.
Насчет логина, кажется, тоже погорячился. Нужно было назваться не Dron, а как нибудь более красноречиво. Что-нибудь вроде "Дребезг контактов" :))
Тему перенес сюда:
http://arduino.ru/forum/proekty/sim800l-peredacha-dannykh-v-tonovom-rezhime
Поделитесь, как подключали. Особенно питание.
Спасибо!