В предыдущих главе мы рассмотрели мы сделали большие шаги построения "умного дома" – оснастили его датчиками и исполнительными устройствами и создали и обеспечили определенную степень автоматизации для создания комфорта и безопасности. Теперь пришло время сделать наш "умный дом" устройством IoT (Интернета вещей), чтобы получить доступ к нему для мониторинга и управления из любой точки мира по сети интернет. Организуем доступ контроллеров нашего дома к сети интернет.
NodeMCU – это плата на основе Wi-Fi модуля ESP8266, что позволяет подключиться ей к сети интернет по Wi-Fi соединению. С Arduino MEGA немного сложнее – необходимы внешние модули для организации доступа к интернет. В качестве внешних модулей часто используется плата Ethenet shield W5100 или W5500. Можно использовать и модули ESP8266, управляя ими по UART. Мы рассмотрим организацию доступа в интернет с использованием GPRS Shield — платы расширения, позволяющая Arduino работать в сетях сотовой связи по технологиям GSM/GPRS для приёма и передачи данных, SMS и голосовой связи.
8.1. Модуль Ai-Thinker A6
В качестве GPRS-Shield мы будем использовать недорогой модуль Ai-Thinker A6 на плате с антенной (см. рис. 8.1). От аналогов отличается низким энергопотреблением. Поддержка стандартных GSM 07.07,07.05 AT-команд, а так же специальных команд AI-THINKER.
Рис. 8.1. Модуль Ai-Thinker A6 на плате с антенной.
Данный модуль работает с российскими операторами Билайн, МТС, Мегафон. Потребляет ток порядка 80мА. Имеет 1 слот под mini SIM-карту. Скорость модуля по умолчанию 115200. Плата может иметь кнопку Пуск, которую необходимо удерживать около 3х секунд. Выпускается на плате, которую можно подключить к питанию +5вольт через микро usb. Модуль поддерживает АТ команды. Работу с компьютером можно производить через преобразователь UART. Имеет возможность отправлять данные по GSRS.
Характеристики модуля:
• Рабочее напряжение: 5В через USB-micro или отдельными контактами;
• Рабочее напряжение чипа: 3.3 - 4.6В;
• Рабочая температура: -30 ... +80 градусов;
• Потребление в активном режиме: 100 - 900 мА;
• Потребление в экономном режиме: 3 мА;
• Скорость UART: по умолчанию 115200бит/с (есть автоопределение);
• GPRS Class 10 : Макс. 85.6 кбит;
• Протоколы : PPP, TCP, UDP, MUX;
• Поддержка PBCCH;
• CSD : до 14,4 кбит;
• SIM / USIM : 3V / 1.8V;
• Голос: подавление эха, подавление шума.
8.2. Управление модулем Ai-Thinker A6 с помощью AT-команд
Рассмотрим управление модулем Ai-Thinker A6 с помощью AT-команд. Для этого подключим модуль к компьютеру, используя переходник FTDI. Схема соединений представлена на рис. 8.2.
Рис. 8.2. Подключение модуля Ai-Thinker A6 к компьютеру.
Подключаем модуль к компьютеру и запускаем программу для общения с последовательным портом. Можно использовать монитор последовательного порта Arduino IDE. Будем отправлять на модуль Ai-Thinker A6 AT-команды. Набор команд аналогичен AT-командам для SIM800 или SIM900, но для выходы в интернет используются специальные команды AI-THINKER.
Для включения модуля необходимо нажать кнопку POWER не меньше 2 секунд, при нажатии мигает красный светодиод, и дальше работать в терминале.Набираем в мониторе последовательного порта следующие команды:
AT+CREG?
если ответ +CREG:0,5 или +CREG:0,5, установим 1:
AT+CREG=1
Далее проверка подключения модуля к GPRS-сети
AT + CGATT?
если ответ +CGATT: 0 установим 1:
AT + CGATT=1
Это может занять много времени и написать COMMAND NO RESPONSE, необходимо повторять и потом поверить командой
AT + CGATT?
Подключаемся к точке доступа оператора связи. Для МТС это будет так:
AT + CGDCONT = 1, "IP", "internet.mts.ru"
AT + CSTT = "internet.mts.ru","mts", "mts"
Далее устанавливаем интернет-соединение:
AT + CGACT = 1,1
В случае ответа OK, можем посмотреть наш динамический IP-адрес:
AT + CIFSR
И затем обращаемся к какому-нибудь серверу, например google.ru
AT + CIPSTART = "TCP", www.google.com ", 80
Весь процесс подключения представлен на рис. 8.3.
Рис. 8.3. Процесс работы с модулем Ai-Thinker A6 в мониторе последовательного порта.
Теперь попробуем подключить модуль Ai-Thinker A6 к плате Arduino и отправить сообщение c данными на сервер, например http://sparcfun.com.
8.3. Подключение модуля Ai-Thinker A6 к плате Arduino MEGA
Подключим модуль Ai-Thinker A6 к плате Arduino MEGA и сделаем тестовую отправку данных по GPRS на удаленный сервер. Схема подключения приведена на рис. 8.4.
Рис. 8.4. Подключение модуля Ai-Thinker A6 к плате Arduino MEGA.
В качестве удаленного сервера для отправки данных удобно использовать сервер data.sparkfun.com – здесь не требуется регистрации и можно быстро проверить правильность отправки данных. На главной странице переходим по ссылке создания бесплатного потока данных (рис. 8.5).
Рис. 8.5. Ссылка для создания бесплатного потока данных.
На странице создания потока заполняем необходимые данные (рис. 8.6):
• Название (Title);
• Описание (Description);
• Приватность (Visible/Hidden);
• Cписок полей (Fields).
и подтверждаем.
Рис. 8.6. Форма создания потока данных.
При создании потока генерируются публичный ключ (Public key), приватный ключ (Private key), которые нам понадобятся при создании скетча отправки данных и страница для просмотра отправленных данных (Public URL) (рис. 8.7).
Рис. 8.7. Данные необходимые для создания программы отправки.
Теперь загрузим на плату Arduino MEGA скетч из листинга 8.1., внеся в него изменения – свои данные Public key и Private key для сервиса data.sparkfun.com и данные к точке доступа своего сотового оператоа (в скетче 8.1 данные для сотового оператора МТС).
Листинг 8.1
#define OK 1
#define NOTOK 2
#define TIMEOUT 3
#define RST 2
#define A6board Serial1
#define A6baud 115200
#define SERIALTIMEOUT 3000
char end_c[2];
void setup() {
A6board.begin(A6baud); // порт Serial1
Serial.begin(115200); // порт Serial
// ctrlZ
end_c[0] = 0x1a;
end_c[1] = '\0';
Serial.println("Start");
}
void loop()
{
Serial.println("Waiting for command");
if (Serial.available())
switch (Serial.read())
{ // проверка команды на отправку данных
case 's':
Serial.println("-Post value to Sparkfun-");
// получение аналоговых данных A0
float batt = (float)analogRead(A0)*5.165/594.0;
// вызов процедуры отправки данных
sendSparkfunGSM(1, batt);
break;
}
if ( A6board.available())
Serial.write( A6board.read());
delay(2000);
}
///отправка данных на sparkfun()///
bool sendSparkfunGSM(byte sparkfunType, float value1) {
String host = "data.sparkfun.com";
String publicKey = "9b1nm53N68cDAOvVEJgK";
String privateKey = "xv9NwElKY7ibJ57Vdaje";
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
A6command("AT+CGATT?", "OK", "yy", 20000, 2);
A6command("AT+CGATT=1", "OK", "yy", 20000, 2);
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
A6command("AT+CSTT=\"internet.mts.ru\",\"mts\",\"mts\"", "OK", "yy", 20000, 2); //bring up wireless connection
A6command("AT+CGDCONT=1,\"IP\",\"internet.mts.ru\"", "OK", "yy", 20000, 2);
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
A6command("AT+CGACT=1,1", "OK", "yy", 10000, 2);
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
A6command("AT+CIFSR", "OK", "yy", 20000, 2); //get IP adress
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
A6command("AT+CIPSTART=\"TCP\",\"" + host + "\",80", "CONNECT OK", "yy", 25000, 2); //start up the connection
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
// отправка данных на сервер
A6command("AT+CIPSEND", ">", "yy", 10000, 1);
delay(500);
A6board.print("GET /input/");
A6board.print(publicKey);
A6board.print("?private_key=");
A6board.print(privateKey);
A6board.print("&battery=");
A6board.print(value1, 2);
A6board.print(" HTTP/1.1");
A6board.print("\r\n");
A6board.print("HOST: ");
A6board.print(host);
A6board.print("\r\n");
A6board.print("\r\n");
Serial.print("GET /input/");
Serial.print(publicKey);
Serial.print("?private_key=");
Serial.print(privateKey);
Serial.print("&battery=");
Serial.print(value1, 2);
Serial.print(" HTTP/1.1");
Serial.print("\r\n");
Serial.print("HOST: ");
Serial.print(host);
Serial.print("\r\n");
Serial.print("\r\n");
A6command(end_c, "HTTP/1.1", "yy", 30000, 1);
A6board.println(end_c); //sending ctrlZ
unsigned long entry = millis();
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
A6command("AT+CIPCLOSE", "OK", "yy", 15000, 1); //sending
A6command("AT+CIPSTATUS", "OK", "yy", 10000, 2);
delay(100);
Serial.println("-End-");
}
byte A6waitFor(String response1, String response2, int timeOut) {
unsigned long entry = millis();
int count = 0;
String reply = A6read();
byte retVal = 99;
do {
reply = A6read();
if (reply != "") {
Serial.print((millis() - entry));
Serial.print(" ms ");
Serial.println(reply);
}
} while ((reply.indexOf(response1) + reply.indexOf(response2) == -2) && millis() - entry < timeOut );
if ((millis() - entry) >= timeOut) {
retVal = TIMEOUT;
} else {
if (reply.indexOf(response1) + reply.indexOf(response2) > -2) retVal = OK;
else retVal = NOTOK;
}
return retVal;
}
byte A6command(String command, String response1, String response2, int timeOut, int repetitions) {
byte returnValue = NOTOK;
byte count = 0;
while (count < repetitions && returnValue != OK) {
A6board.println(command);
Serial.print("Command: ");
Serial.println(command);
if (A6waitFor(response1, response2, timeOut) == OK) {
returnValue = OK;
} else returnValue = NOTOK;
count++;
}
return returnValue;
}
bool A6begin() {
A6board.println("AT+CREG?");
byte hi = A6waitFor("1,", "5,", 1500);
while ( hi != OK) {
A6board.println("AT+CREG?");
hi = A6waitFor("1,", "5,", 1500);
}
if (A6command("AT&F0", "OK", "yy", 5000, 2) == OK) {
if (A6command("ATE0", "OK", "yy", 5000, 2) == OK) {
if (A6command("AT+CMEE=2", "OK", "yy", 5000, 2) == OK)
return OK;
else return NOTOK;
}
}
}
void ShowSerialData()
{
unsigned long entry = millis();
while ( A6board.available() != 0 && millis() - entry < SERIALTIMEOUT)
Serial.println(A6board.readStringUntil('\n'));
}
String A6read() {
String reply = "";
if (A6board.available()) {
reply = A6board.readString();
}
return reply;
}
После загрузки скетча на плату Arduino запускаем монитор последовательного порта и при отправке символа s происходит процесс инициализации отправки данных с аналогового входа A0 в сервис data.sparkfun.com (см. рис. 8.8).
Рис. 8.8. Отображение в мониторе процесса отправки данных в сервис data.sparkfun.com
Скачать данный скетч можно на сайте www.arduino-kit.ru по ссылке.
8.4. Подключение модуля NodeMCU к сети Интернет по Wi-Fi.
Рассмотрим подключение платы NodeMCU к сети интернет. Для этого необходимо подключиться по Wi-Fi к точке доступа, имеющей выход в интернет. Загрузим в плату NodeMCU скетч подключения к Wi-Fi точке доступа и отправки данных в сервис data.sparkfun.com (листинг 8.2), измените данные на свои для подключения к точке доступа и в сервисе data.sparkfun.com:
const char* ssid = "my_point";
const char* password = " my_point pass";
const char* host = "data.sparkfun.com";
const char* streamId = "---------------------";
const char* privateKey = "---------------------";
Листинг 8.2
#include <ESP8266WiFi.h>
const char* ssid = "my_point ";
const char* password = "my_point pass ";
const char* host = "data.sparkfun.com";
const char* streamId = "---------------------";
const char* privateKey = "---------------------";
void setup() {
Serial.begin(115200);
delay(10000);
// подсоединение к WiFi точке доступа
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
float value = 0;
void loop() {
delay(10000);
Serial.print("connecting to ");
Serial.println(host);
// создаем TCP соединение
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
// создаем строку URL
String url = "/input/";
url += streamId;
url += "?private_key=";
url += privateKey;
url += "&battery=";
value=3.3*analogRead(A0)/1024;
url += value;
Serial.print("Requesting URL: ");
Serial.println(url);
// отправить данные на сервер
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delay(10);
// ответ сервера
while(client.available()){
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("closing connection");
}
После загрузки скетча на плату запускаем монитор последовательного порта и наблюдаем процесс отправки данных с аналогового входа A0 в сервис data.sparkfun.com (см. рис. 8.9) каждые 10 секунд.
Рис. 8.9. Отображение в мониторе процесса отправки данных в сервис data.sparkfun.com
Скачать данный скетч можно на сайте www.arduino-kit.ru по ссылке.