Встречайте убийцу Arduino: ESP8266

0
3852
Встречайте убийцу Arduino: ESP8266
Встречайте убийцу Arduino: ESP8266

Wi-Fi является важной составляющей комплекта для любого проекта Интернета вещей (IoT), но любимое многими Arduino не имеет Wi-Fi, а добавление шилда Wi-Fi может увеличить общую стоимость почти до $40. Что делать, если уже есть Arduino-совместимая плата с встроенным Wi-Fi менее чем за $10?.

 

Встречайте убийцу Arduino: ESP8266. Это только вопрос времени, прежде чем была украдена корона из блестящей головы нашей дорогой платы разработчика Arduino.

ESP-12E (также известный как NodeMCU) был сначала в продаже как надстройка Wi-Fi низкой стоимости для платы Arduino, пока сообщество хакеров не понятно, что можно было бы полностью обойтись без Arduino.

Менее чем за год, ESP8266 взлетела в популярности и теперь настолько хорошо поддерживается и отработана, что, если вы сегодня используете Arduino, то должны встать и принять ее к сведению. Купить ее сейчас же и следовать этом руководстве, чтобы начать программировать ESP8266 — и все это из знакомого Arduino IDE.

Вы не ограничены использованием Arduino IDE, конечно, — плата тоже совместима с Lua (который выглядит как похудевший Python для начинающих), но так как мы предлагаем замену с точки зрения тех, кто научился на Arduino, то сегодня рассмотрим исключительно Arduino IDE.

Сегодня достаточно много моделей ESP8266, но автор собирается пойти дальше и рекомендует ESP-12E (также известный как NodeMCU 1.0, или это новейший брат NodeMCU 2.0).

Модуль немного дороже, чем другие ($6.50 в сравнении с $4!), Но включает в себя последовательный драйвер, необходимый для программирования чипа, имеет встроенный регулятор питания, а также много выводов входов/выходов. Он широко поддерживается и действительно ничего, кроме подключения USB для программирования и питания, больше не нужно, поэтому с ним легче работать. Если покупаете любую другую плату ESP8266, то, возможно, будет нужен отдельный регулятор питания для 3,3 В и соответствующее FTDI-соединения для программирования.

Начало работы с ESP8266-12E и Arduino

Во-первых, установите драйверы последовательного порта для этой платы. Возможно, потребуетсяотключить KEXT подписания, если работаете El Capitan, в связи с новыми системами безопасности.

Далее, вы должны включить поддержку ESP8266 диспетчером платы Arduino IDE. Откройте Preferences (Настройки) и введите следующий адрес в окне, где указано Additional Board Manager URLs (Дополнительные адреса диспетчера платы):

http://arduino.esp8266.com/package_esp8266com_index.json

Нажмите ОК, затем откройте Boards Manager (Диспетчер платы) из меню Tools -> Board, найдите esp8266 и установите платформу. Теперь вы должны увидеть выбор для NodeMCU 1.0:

select-board-_3

Оставьте процессор и скорость загрузки такими, какие есть, и выберите опять установки последовательного порта. На Mac, это выглядит как cu.SLAB_USBtoUART.

Как первую программу, автор предлагает простой Wi-Fi сканер — найдите его в File -> Examples -> ESP8266WiFi -> WifiScan. Обратите внимание, что загрузка довольно медленный, но в конечном итоге будет показано done uploading (загрузка сделано) и в этот момент (не раньше, ибо нарушите процесс загрузки), можете открыть Serial Monitor. Должны увидеть нечто похожее на это:

wifi-scan-test-esp_4

Удача! Теперь, давайте попробуем подключиться к плате.

Возьмем совсем простой код для подключения к сети Wi-Fi. Он ничего, кроме простого подключения, не делает, но еще что-то сможете добавить позже. Только не забывайте изменить YOUR_SSID и YOUR_PASSWORD на параметры своего Wi-Fi. Загрузите, откройте консоль на последовательном порту, и вы должны увидеть это подключение:

#include
const char* ssid = «YOUR_SSID»;
const char* password = «YOUR_PASSWORD»;

WiFiClient wifiClient;

void setup() {
Serial.begin(115200);
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());
}

void loop() {

}

Разве это не здорово, что все было до смешного просто?

Прежде, чем продолжить, вот схема выводов — она может пригодится в дальнейшем. Обратите внимание, что номера контактов, указанных в коде, являются номерами GPIO, а не D0-16, вероятно, написанных на печатной плате. Если совершенно не можете понять, почему датчик не работает, то, вероятно, спутали номера выводов.

NodeMCU__v1.0_pinout_5

Быстрый датчик умного дома с MQTT и DHT11

Рассмотрим практический пример, который можно использовать сразу, чтобы контролировать ваш дом. Будем снимать значения температуры и влажности с датчика DHT11, и добавлять к отчету, используя протокол MQTT в сети Wi-Fi, в случае автора, к системе автоматизации дома OpenHAB (если нет, то, возможно, захотите прочитать Руководство для начинающих, чтобы получить OpenHAB и запустить на Raspberry Pi, и 2 часть, в которой конкретно рассматривается установка сервера MQTT).

На стороне монтажа подключите датчик DHT к GND, 3,3 В и ~ D4 (или GPIO 2). Это все, что нам сейчас нужно.

Загрузите библиотеки MQTT и DHT. Даже если у вас они уже есть, загрузите их в любом случае, сделайте резервное копирование того, что у вас есть, и перезапишите загруженными. Последняя библиотека DHT11 от Adafruit использует алгоритм автоматического определения скорости, с которой данные считываются с датчика, но она глючит на ESP8266 и 90% времени результаты не удается прочитать.

Со старой версией 1.0 библиотеки, которую автор включил в загрузки, вы можете вручную изменить время: 11 лучше подходит для этих плат ESP2866. Автор также прошел через много копий библиотеки MQTT, пытаясь найти хорошую функцию обратного вызова, наконец, один из них включил в загрузки. Надо будет перезапустить Arduino IDE после их замены.

Здесь хранится полный код проекта. Сверху находятся все переменные, которые вы должны изменить, в том числе, параметры Wi-Fi, сервера MQTT (можно использовать URL-адрес вместо использования облачного сервера, хотя на месте нет никакой аутентификации), и каналы для публикации данных.

/* ESP8266 + MQTT Humidity and Temperature Node
* Можно также принимать команды; задействуйте функцию messageReceived()
* Смотри MakeUseOf.com для полного руководства и инструкций
* Автор: James Bruce, 2015
*/

#include <MQTTClient.h>
#include <ESP8266WiFi.h>
#include <DHT.h>

const char* ssid = «YOUR_SSID»;
const char* password = «YOUR_PASSWORD!»;

char* subscribeTopic = «openhab/parentsbedroom/incoming»; // подписаться на эту тему; все, что направляется сюда, будет передано в функцию messageReceived
char* tempTopic = «openhab/parentsbedroom/temperature»; //тема для публикации прочитанной температуры
char* humidityTopic = «openhab/parentsbedroom/humidity»; // публикация прочитанной влажности
const char* server = «192.168.1.99»; // сервер или URL брокера MQTT
String clientName = «parentsbedroom-«; // просто имя, используемое для обращения к MQTT брокера
long interval = 60000; //(ms) — 60 секунд между отчетами
unsigned long resetPeriod = 86400000; // 1 день – это период после которого мы делаем рестарт CPU, чтобы исключить ошибки утечки памяти

#define DHTTYPE DHT11 // DHT11 или DHT22
#define DHTPIN 2

unsigned long prevTime;
DHT dht(DHTPIN, DHTTYPE,11);
float h, t;

WiFiClient wifiClient;
MQTTClient client;

String macToStr(const uint8_t* mac)
{
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
if (i < 5)
result += ‘:’;
}
return result;
}

void setup() {
Serial.begin(115200);
dht.begin();
client.begin(server,wifiClient);
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());

// Генерируем имя клиента, основываясь на MAC-адресе и последних 8 битах счетчика микросекунд
uint8_t mac[6];
WiFi.macAddress(mac);
clientName += macToStr(mac);
clientName += «-«;
clientName += String(micros() & 0xff, 16);

Serial.print(«Connecting to «);
Serial.print(server);
Serial.print(» as «);
Serial.println(clientName);

if (client.connect((char*) clientName.c_str())) {
Serial.println(«Connected to MQTT broker»);
Serial.print(«Subscribed to: «);
Serial.println(subscribeTopic);
client.subscribe(subscribeTopic);

}
else {
Serial.println(«MQTT connect failed»);
Serial.println(«Will reset and try again…»);
abort();
}

prevTime = 0;
}

void loop() {
static int counter = 0;

if(prevTime + interval < millis() || prevTime == 0){
prevTime = millis();
Serial.println(«checking again»);
Serial.println(prevTime);

h = dht.readHumidity();
t = dht.readTemperature();

h = h*1.23;
t = t*1.1;

// Проверяем, не было какой-либо ошибки при чтении и выходим раньше (чтобы попробовать снова).
if (isnan(h) || isnan(t)) {
Serial.println(«Failed to read from DHT sensor!»);
}
else if(!client.connected()){
Serial.println(«Connection to broker lost; retrying»);
}
else{
char* tPayload = f2s(t,0);
char* hPayload = f2s(h,0);

Serial.println(t);
Serial.println(h);

Serial.println(tPayload);
Serial.println(hPayload);

client.publish(tempTopic, tPayload);
client.publish(humidityTopic, hPayload);

Serial.println(«published environmental data»);
}

}

client.loop();

// Сброса через день для избежания утечки памяти
if(millis()>resetPeriod){
ESP.restart();
}
}

/* значение с плавающей запятой в строку
* f — преобразование значения с плавающей запятой в строку
* p — точность (количество знаков)
* вернуть строковое представление значения с плавающей запятой
*/
char *f2s(float f, int p){
char * pBuff; // используем, чтобы помнить, какая часть буфера использована для dtostrf
const int iSize = 10; // количество буферов, по одному для каждого значения с плавающей запятой для упаковки
static char sBuff[iSize][20]; // пространство 20 символов, включая NULL, для каждого значения с плавающей запятой
static int iCount = 0; // сохраняем таблицу следующего размещения в sBuff для использования
pBuff = sBuff[iCount]; // используем этот буфер
if(iCount >= iSize -1){ // проверка упаковки
iCount = 0; // если упаковано, то опять стартуем и сбрасываем
}
else{
iCount++; // продвинутый счетчик
}
return dtostrf(f, 0, p, pBuff); // вызов библиотечной функции
}

void messageReceived(String topic, String payload, char * bytes, unsigned int length) {
Serial.print(«incoming: «);
Serial.print(topic);
Serial.print(» — «);
Serial.print(payload);
Serial.println();
}

Кодesp8266_mqtt_humtemp на GitHub

Опишем, как это работает, и несколько замечаний:

• Сначала подключаемся к Wi-Fi, затем к серверу MQTT, а потом начинаем основной цикл loop().

• В цикле мы опрашиваем датчик DHT каждые 60 секунд и публикуем показания на соответствующих MQTT-каналах. Опять же, если найдете в большинстве чтений результатов сообщение об ошибке, то у вас неправильная версия библиотеки DHT – надо уменьшить ее до v1.0.

• client.loop() передает управление в библиотеку MQTT, что позволяет реагировать на входящие сообщения.

• Функция messageReceived() позволяет обрабатывать входящие сообщения — просто добавьте простое условие if, чтобы сравнить полученное сообщение с тем, что ожидали. Это можно использовать, чтобы активировать, например, реле.

• После выполнения кода в течение нескольких дней, автор обнаружил, что код случайно перестал работать — автор считает это своего рода утечкой памяти, учитывая, что он не имел навыков кодирования для борьбы с ним, также это может быть связано с основными библиотеками. Автор выбрал простое мягкое перезагрузки каждый день. Поэтому, за один день узлы датчиков сначала активируются, а потом перезапускають себя.

• При питании дешевых модулей DHT11 от 3,3 В значение влажности намного ниже, чем они должны быть. Автор решил эту проблему простым умножением и калибровкой по коммерческим датчиком. Он советовал бы вам получить подтверждение от своего доверенного источника, прежде чем полагаться на показания. Кроме того, питать их от 5В — но вы должны разместить переключения логического уровня 5В-3.3 В между выводом данных и ESP8266, чтобы не повредить модуль.

Если все получилось хорошо, то теперь вы должны получать показания датчиков в своем брокере MQTT, и можете продолжить с подключением их к OpenHAB, как указано в части 2 руководства для начинающих, где автор также показал, как построить график данных.

humdity-graph-from-openhab_6

Прощай Arduino, мы так любили тебя. Шутка, потому что не везде даже в своем доме можете иметь Wi-Fi, поэтому для таких пятен все еще нужна ячеистая сеть с Arduino и радиоприемников.