====== GPRS-логгер для теплицы ======
{{ :projects:gprslogger:gprslogger_overview.jpg?nolink&700 |}}
* Платформы: Iskra Neo
* Языки программирования: Arduino (C++)
* Тэги: GPRS, SIM900, теплица, мониторинг погоды, конструктор ПВХ.
===== Что это? =====
Каждый садовод и дачник знает, чтобы собрать хороший урожай, необходимо уйму времени провести на огороде. Но вряд ли кому-нибудь придёт в голову находиться круглые сутки возле любимой грядки. А ведь так хочется, находясь дома или на работе, быть уверенным, что твоим помидоркам ничего не угрожает.
Одним из инструментов для решения этой задачи является мобильный Интернет. В этой статье мы расскажем как собрать устройство, способное осуществлять постоянный мониторинг окружающей среды, считывая данные с различных датчиков, и передавать их на популярный сервис «[[http://narodmon.ru/|народный мониторинг]]», используя GPRS.
===== Что нам понадобится? =====
{{ :projects:gprslogger:gprslogger_parts.jpg?nolink&700 |}}
- [[amp>product/iskra-neo?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | Iskra Neo]]
- [[amp>product/arduino-gprs-shield?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | GPRS Shield]]
- [[amp>product/arduino-troyka-shield?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | Troyka Shield]]
- [[amp>product/soil-moisture-sensor?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | Датчик влажности почвы]]
- [[amp>product/gas-sensor-mq2?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | Датчик газа MQ2 ]]
- [[amp>product/troyka-light-sensor?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | Датчик освещённости (Troyka-модуль) ]]
- [[amp>product/temperature-humidity-sensor-dht11?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | Датчик температуры и влажности DHT11 ]]
- [[amp>product/usb-cable-micro?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | Кабель USB (A — Micro USB)]]
- Крепёжные элементы: винты, саморезы, гайки
- SIM-карта
- Конструктор ПВХ
===== Как собрать? =====
- Возьмите платформу Iskra Neo и нижнюю панель кубa (7x7), соедините её с помощью винтов и гаек, так чтобы гайки располагались между панелью и платформой.{{ :projects:gprslogger:gprslogger_build1.jpg?nolink&700 |}}
- Вставьте сим-карту в GPRS Shield и установите его сверху на платформу Iskra Neo.{{ :projects:gprslogger:gprslogger_build2.jpg?nolink&700 |}}
- Боковые панели куба (7x7) соедините с нижней панелью (7x7). Установите Troyka Shield сверху на GPRS Shield.{{ :projects:gprslogger:gprslogger_build3.jpg?nolink&700 |}}
- Возьмите панель куба (7x5) и, спользуя винты или саморезы, закрепите на ней датчик газа MQ2 и датчик температуры и влажности DHT11.{{ :projects:gprslogger:gprslogger_build4.jpg?nolink&700 |}}
- Используя 3-проводные шлейфы, подключите через Troyka Shield датчик газа MQ2 к аналоговому пину ''A2'', а цифровой датчик DHT11 к цифровому пину ''11''. Далее панель куба (7x5) с установленными датчиками закрепите между боковыми панелями куба, так чтобы датчики были направлены внутрь.{{ :projects:gprslogger:gprslogger_build5.jpg?nolink&700 |}}
- Возьмите переднюю панель куба (6x7) и соедините её с нижней панелью и панелью с датчиками, заранее откусив бокорезами секции, мешающие выводу антенны. Прикрутите антенну в SMA-разъём.{{ :projects:gprslogger:gprslogger_build6.jpg?nolink&700 |}}
- Возьмите датчик освещённости, прикрутите его к панели для крепления Troyka-модулей, и с помощью четырёх панелей конструктора (3x2) соорудите «башенку».{{ :projects:gprslogger:gprslogger_build7.jpg?nolink&700 |}}
- В продолжение установите «башенку» с датчиком на верхнюю панель куба (7x7), и установите получившуюся конструкцию на левую, правую и заднюю панели. Подключите датчик освещённости через стандартный 3-проводные шлейф через Troyka Shield к аналоговому пину ''A4''.{{ :projects:gprslogger:gprslogger_build8.jpg?nolink&700 |}}
- Заднюю панель куба (7x3) закрепите между левой и правой панелями внизу, напротив разъёмов USB и внешнего питания платформы Iskra Neo, заранее отделив бокорезами секции, мешающие ей устойчиво зафиксироваться.{{ :projects:gprslogger:gprslogger_build9.jpg?nolink&700 |}}
- Подключите датчик влажности почвы через 3-проводной шлейф через Troyka Shield к аналоговому пину ''A0''. В результате должна получиться такая схема:{{ :projects:gprslogger:gprslogger_scheme.png?nolink&700 |}}
- Возьмите заднюю панель куба (7x2) и установите её между левой и правой панелями в верхней части. В заключение возьмите панель крестиков (1x6) и установите между задними панелями (7x3) и (7x2).{{ :projects:gprslogger:gprslogger_build10.jpg?nolink&700 |}}
===== Алгоритм =====
* Сразу после подачи питания проверяем есть ли связь с GPRS устройством.
* Если связи нет, повторяем запрос снова и ждём подтверждения связи.
* Пытаемся установить GPRS-соединение с заданными настройками.
* Если GPRS-соединения нет, повторяем попытку снова и ждём подтверждения.
* Пытаемся подключиться к серверу.
* Если подключение нет, повторяем запрос снова и ждём подтверждения сервера.
* Считываем значения с датчиков.
* Формируем и оправляем TCP-запрос в специальном формате для «народного мониторинга»
* Повторяем весь выше описанный цикл каждые 5 минут.
===== Исходный код =====
// библиотека для работы с GPRS устройством
#include
// библиотека для эмуляции Serial-порта
// она нужна для работы библиотеки GPRS_Shield_Arduino
#include
// библиотека для работы с датчиком DHT11
#include
// даём разумное имя для пина к которому подключен датчик DHT11
#define DHT11_PIN 11
// даём разумное имя для пина к которому подключен датчик влажности почвы
#define MOISTURE_PIN A0
// даём разумное имя для пина к которому подключен датчик уровня CO2
#define MQ2_PIN A2
// даём разумное имя для пина к которому подключен датчик уровня освещённости
#define LIGHT_PIN A4
// IMEI GPRS Shield, он указан на лицевой стороне шилда
// по IMEI устройство будет идентифицироваться в проекте
// поэтому он должен быть уникальным
#define IMEI "868204005187692"
// часть запроса в специальном формате для народного мониторинга, содержащая:
// IMEI устройства, название фирмы и GPS-координаты
#define CLIENT "#"IMEI"#Амперка#55.7467#37.6627#2.0\r\n"
// интервал между отправками данных в миллисекундах (5 минут)
#define INTERVAL 300000
// размер массива, содержащий TCP-запрос
#define LEN 370
// буфер для отправки данных на народный мониторинг
// согласно установленной сервисом форме
char tcpBuffer[LEN];
// переменная для хранения времени работы программы
// с последнего запуска отправки данных на сервер
unsigned long previousMillis = 0;
// переменная температуры воздуха
int temp = 0;
// переменная влажности воздуха
int humi = 0;
// переменная влажности почвы
int moisture = 0;
// переменная уровня CO2
int mq2 = 0;
// переменная уровня освещённости
int light = 0;
// создаём объект класса dht11
dht11 DHT;
// создаём объект класса GPRS и передаём в него объект Serial1
GPRS gprs(Serial1);
// можно указать дополнительные параметры — пины PK и ST
// по умолчанию: PK = 2, ST = 3
// GPRS gprs(Serial1, 2, 3);
void setup()
{
// открываем последовательный порт для мониторинга действий в программе
Serial.begin(9600);
// открываем Serial-соединение с GPRS Shield
Serial1.begin(9600);
}
void loop()
{
// включаем GPRS шилд
gprs.powerOn();
// проверяем есть ли связь с GPRS устройством
while (!gprs.init()) {
// если связи нет, ждём 1 секунду
// и выводим сообщение об ошибке
// процесс повторяется в цикле
// пока не появится ответ от GPRS устройства
delay(1000);
Serial.print("GPRS Init error\r\n");
}
// вывод об удачной инициализации GPRS Shield
Serial.println("GPRS init success");
delay(3000);
// пытаемся установить GPRS-соединение
// с заданными настройками, которые предоставляются операторами связи
while (!gprs.join("internet.beeline.ru", "beeline", "beeline")) {
// если GPRS-соединения нет
// выводим сообщение об ошибке и ждём 1 секунду
// процесс повторяется в цикле
// пока не появится положительный ответ от GPRS устройства
Serial.println("Gprs join network error");
delay(1000);
}
// выводим сообщение об удачной установке GPRS-соединения
Serial.println("GPRS OK");
// получаем и выводим локальный IP адрес
Serial.print("IP Address is ");
Serial.println(gprs.getIPAddress());
// пытаемся подключиться к серверу
// указывая тип соединения, адрес сервера и номер порта
while (!gprs.connect(TCP, "narodmon.ru", 8283)) {
// если сервер не отвечает или отвечает ошибкой
// выводим сообщение об ошибке и ждём 1 секунду
// процесс повторяется в цикле
// пока не появится положительный ответ от сервера
Serial.println("Connect error");
delay(1000);
}
// выводим сообщение об удачном подключении к серверу
Serial.println("Connect success");
// вызываем функцию считывания всех показателей с датчиков
readSensors();
// выводим показания датчиков в последовательный порт
serialPrint();
// вызываем функцию, которая формирует и отправляет tcp-запрос
// в специальном формате для «народного мониторинга»
tcpRequest();
// разрываем все GPRS-соединения
gprs.close();
// деактивируем интерфейс GPRS
gprs.disconnect();
// выводим сообщение об удачном завершении операции
Serial.println("OK");
// выключаем GPRS-шилд
gprs.powerOff();
// проверяем не прошел ли нужный интервал времени
while (millis() - previousMillis < INTERVAL) {
// ждём 5 минут
}
//если прошел, то сохраняем текущее время
previousMillis = millis();
}
// функция записи данных с датчиков в массив
// в специальном формате для «народного мониторинга»
void tcpRequest()
{
/* помните, что при выполнении операций
с массивами символов, например strcat(str1, str2);
контроль нарушения их границ не выполняется,
поэтому программист должен сам позаботиться
о достаточном размере массива str1,
позволяющем вместить как его исходное содержимое,
так и содержимое массива str2
*/
// добавляем к строке tcpBuffer строку CLIENT
strcat(tcpBuffer, CLIENT);
// функция добавления в TCP-запрос значения температуры воздуха
tcpTemp();
// функция добавления в TCP-запрос значения влажности воздуха
tcpHumi();
// функция добавления в TCP-запрос значения влажности почвы
tcpMoisture();
// функция добавления в TCP-запрос состояния уровня CO2
tcpGas();
// функция добавления в TCP-запрос значения освещённости
tcpLight();
// добавляем к строке tcpBuffer два символа «##»,
// которые свидетельствуют об окончании запроса
strcat(tcpBuffer, "##");
// отправляем массив TCP-запроса на сервис «народного мониторинга»
gprs.send(tcpBuffer);
// очищаем буфер
clearTcpBuffer();
}
// Функция добавление в TCP-запрос данные о температуре воздуха
void tcpTemp()
{
// переменная для символьного представления
// значения температуры воздуха
char s_temp[8];
// преобразуем целое число 10 системы исчисления
// из переменной temp в строковое представление в массив s_temp[]
itoa(temp, s_temp, 10);
// добавляем к буферу символы «.00», для дробной части
strcat(s_temp, ".00");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу уникальный серийный номера датчика
// получаем его путём добавления к IMEI GPRS-шилда названия датчика
strcat(tcpBuffer, IMEI);
strcat(tcpBuffer, "T01");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу строку s_temp
strcat(tcpBuffer, s_temp);
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу время актуальности показаний
// если показания датчиков передаются немедленно,
// то данный параметр передавать не надо
strcat(tcpBuffer, " ");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу названия датчика
strcat(tcpBuffer, "Датчик температуры");
strcat(tcpBuffer, "\r\n");
}
// Функция добавление в TCP-запрос данные о влажности воздуха
void tcpHumi()
{
// переменная для символьного представления
// значения влажности воздуха
char s_humi[8];
// преобразуем целое число 10 системы исчисления
// из переменной humi в строковое представление в массив s_humi[]
itoa(humi, s_humi, 10);
// добавляем к буферу символы «.00», для дробной части
strcat(s_humi, ".00");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу уникальный серийный номера датчика
// получаем его путём добавления к IMEI GPRS-шилда названия датчика
strcat(tcpBuffer, IMEI);
strcat(tcpBuffer, "H01");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу строку s_humi
strcat(tcpBuffer, s_humi);
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу время актуальности показаний
// если показания датчиков передаются немедленно,
// то данный параметр передавать не надо
strcat(tcpBuffer, " ");
strcat(tcpBuffer, "#");
// добавляем к буферу названия датчика
strcat(tcpBuffer, "Датчик влажности");
strcat(tcpBuffer, "\r\n");
}
void tcpMoisture()
{
// переменная для символьного представления
// значения влажности почвы
char s_moisture[8];
// преобразуем целое число 10 системы исчисления
// из переменной moisture в строковое представление в массив s_moisture[]
itoa(moisture, s_moisture, 10);
// добавляем к буферу символы «.00», для дробной части
strcat(s_moisture, ".00");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу уникальный серийный номера датчика
// получаем его путём добавления к IMEI GPRS-шилда названия датчика
strcat(tcpBuffer, IMEI);
strcat(tcpBuffer, "H02");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу строку s_moisture
strcat(tcpBuffer, s_moisture);
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу время актуальности показаний
// если показания датчиков передаются немедленно,
// то данный параметр передавать не надо
strcat(tcpBuffer, " ");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу названия датчика
strcat(tcpBuffer, "Датчик влажности почвы");
strcat(tcpBuffer, "\r\n");
}
void tcpGas()
{
// переменная для символьного представления значения CO2
char s_mq2[8];
// преобразуем целое число 10 системы исчисления
// из переменной mq2 в строковое представление в массив s_mq2[]
itoa(mq2, s_mq2, 10);
// добавляем к буферу символы «.00», для дробной части
strcat(s_mq2, ".00");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу уникальный серийный номера датчика
// получаем его путём добавления к IMEI GPRS-шилда названия датчика
strcat(tcpBuffer, IMEI);
strcat(tcpBuffer, "MQ2");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу строку s_gas
strcat(tcpBuffer, s_mq2);
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу время актуальности показаний
// если показания датчиков передаются немедленно,
// то данный параметр передавать не надо
strcat(tcpBuffer, " ");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу названия датчика
strcat(tcpBuffer, "Датчик CO2");
strcat(tcpBuffer, "\r\n");
}
void tcpLight()
{
// переменная для символьного представления значения освещённости
char s_light[8];
// преобразуем целое число 10 системы исчисления
// из переменной light в строковое представление в массив s_light[]
itoa(light, s_light, 10);
// добавляем к буферу символы «.00», для дробной части
strcat(s_light, ".00");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу уникальный серийный номера датчика
// получаем его путём добавления к IMEI GPRS-шилда названия датчика
strcat(tcpBuffer, IMEI);
strcat(tcpBuffer, "L01");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу строку s_light
strcat(tcpBuffer, s_light);
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу время актуальности показаний
// если показания датчиков передаются немедленно,
// то данный параметр передавать не надо
strcat(tcpBuffer, " ");
// добавляем к буферу разделительный символ «#»
strcat(tcpBuffer, "#");
// добавляем к буферу названия датчика
strcat(tcpBuffer, "Датчик освещения");
strcat(tcpBuffer, "\r\n");
}
// функция считывания показателей с датчиков
void readSensors()
{
// считывание данных с датчика DHT11
DHT.read(DHT11_PIN);
// присваивание переменной temp значения температуры воздуха
temp = DHT.temperature;
// присваивание переменной humi значения влажности воздуха
humi = DHT.humidity;
// считывание значения с датчика влажности почвы
moisture = analogRead(MOISTURE_PIN);
// считывание значения с датчика уровня CO2
mq2 = analogRead(MQ2_PIN);
// считывание значения с датчика уровня освещённости
light = analogRead(LIGHT_PIN);
// преобразовываем аналоговое 10-битное значение
// датчика влажности почвы в диапазон (от 0% до 100%)
moisture = map(moisture, 0, 1023, 0, 100);
// преобразовываем аналоговое 10-битное значение
// датчика уровня CO2 в диапазон (от 0ppm до 8000ppm)
mq2 = map(mq2, 0, 1023, 0, 8000);
// преобразовываем аналоговое 10-битное значение
// датчика уровня освещённости в диапазон (от 0Lx до 2000Lx)
light = map(light, 0, 1023, 2000, 0);
}
void clearTcpBuffer()
{
for (int t = 0; t < LEN; t++) {
// очищаем буфер,
// присваивая всем индексам массива значение 0
tcpBuffer[t] = 0;
}
}
// функция вывода значения датчиков в последовательный порт
void serialPrint()
{
Serial.print("temp = ");
Serial.println(temp);
Serial.print("humi = ");
Serial.println(humi);
Serial.print("moisture = ");
Serial.println(moisture);
Serial.print("CO2 = ");
Serial.println(mq2);
Serial.print("light = ");
Serial.println(light);
Serial.println("");
}
Для работы выше приведённого скетча вам понадобятся две библиотеки:
* [[https://github.com/amperka/gprs-shield|Библиотека SIM900 для удобства работы с платой]]
* Библиотека {{:projects:gprslogger:dht11.rar|DHT11}} позволяющая считывать данные с датчика DHT11.
===== Регистрация GPRS-логгера в «Народном мониторинге» =====
Как же нам проверить показания датчиков после того, как мы отправили их на сервер «Народного мониторинга? Помимо хранение данных с различных датчиков, «Народный мониторинг» позволяет видеть их в реальном времени через Интернет с привязкой к карте, а также строить на их основании графики и таблицы. При чем загружать на сайт можно самые разные данные: это может быть информация о климатических условиях или, например, данные о напряжении в сети, потребляемой энергии, даже фото и видео с веб-камер.
Для просмотра значений с датчиков необходимо выполнить следующее:
- Зайдите в браузере на сервис «[[http://narodmon.ru/|народный мониторинг]]».{{ :projects:gprslogger:gprslogger_map.png?nolink&683 |}}
- Зарегистрируйтесь и пройдите авторизацию.
- Добавьте в список новое устройство:
Датчики
Добавить моё устройство
и введите IMEI вашего GPRS Shield.
После этого откроется меню со списком датчиков, где можно будет просмотреть данные за определённый промежуток времени, построить на их основании графики или же вывести значения в таблицу.{{ :projects:gprslogger:gprslogger_map2.png?nolink&683 |}}
===== Демонстрация работы устройства =====
{{youtube>KDrEfaBqe6Y?large}}
===== Что дальше? =====
Данное устройство можно использовать в самых разнообразных целях. Например если к нему подключить автономное питание, можно узнавать если ли в доме электричество, а с помощью [[amp>collection/proximity-sensors?utm_source=proj&utm_campaign=gprslogger&utm_medium=wiki | датчиков пространства]] предостеречь ваш дом от проникновения недоброжелателей.