Arduino + ESP8266 с нуля на примере Wi-Fi термометра, часть первая
Часть 1. Подготовка ESP8266
Зачем эта статья? На хабре уже есть ряд статей про использование ESP в разных конфигурациях, но почему-то без подробностей о том, как именно все подключается, прошивается и программируется. Типа «я взял ESP, две пальчиковые батарейки, DHT22, закинул в коробку, потряс часик и термометр готов!». В итоге, получается странно: те, кто уже работают с ESP не видят в сделанном ничего необычного, а те, кто хочет научиться — не понимают с чего начать. Поэтому, я решил написать подробную статью о том, как подключается и прошивается ESP, как его связать с Arduino и внешним миром и какие проблемы мне попадались на этом пути. Ссылки на Aliexpress привожу лишь для представления порядка цен и внешнего вида компонентов.
Итак, у меня было два микроконтроллера, семь разных сенсоров, пять источников питания, температурный датчик DHT22 и целое множество проводков всех сортов и расцветок, а так же бессчетное количество сопротивлений, конденсаторов и диодов. Не то, чтобы все это было необходимо для термометра, но если уж начал заниматься микроэлектроникой, то становится трудно остановиться.
Питание
Для работы ESP8266 нужно напряжение 3.3В и ток не ниже 300мА. К сожалению, Arduino Uno не в состоянии обеспечить такой ток, как не в состоянии обеспечить его и переходники USB-UART (программаторы) типа FT232RL — их предел около 50мА. А значит придется организовать отдельное питание. И лучше бы, чтобы Arduino тоже работал от 3.3В, чтобы избежать проблем типа «я подал пятивольтовый сигнал на вывод RX модуля ESP, почему пахнет паленой пластмассой?».
Есть три решения.
1. Купить готовый блок питания на 3.3В.
2. Купить готовый модуль с регулятором напряжения, понижающий 5В до 3.3В. Пожалуй, это самый удобный вариант.
3. Собрать модуль самому из регулятора AMS1117 и одного танталового конденсатора на 22мкФ.
Я выбрал третий пункт, поскольку мне часто нужно 3.3В, я жадный и я люблю встраивать регуляторы прямо в блоки питания.
С AMS1117 все просто: если положить его текстом вверх, то напряжение на ногах растет слева направо: 0(Gnd), 3.3В (Vout), 5В (Vin).
Между нулем и выходом нужен танталовый конденсатор на 22мкФ (так по инструкции, что будет если поставить электролитический — я не проверял). У танталового SMD-конденсатора плюс там, где полоска. Немного чудовищной пайки совершенно не предназначенных для такого варварства SMD-компонентов и:
Обязательно проверяйте выходное напряжение. Если оно значительно меньше 3.3В (например, 1.17В) — дайте регулятору остыть после пайки и проверьте контакты. Если поставите конденсатор больше, чем на 22мкФ, то мультиметр может показать более высокое напряжение.
Почему именно AMS1117? Он широко используется. Его вы можете найти почти везде, даже в Arduino Uno, как правило, стоит AMS1117-5.0.
Если вы знаете что-то схожих габаритов и цены, еще более простое в использовании — напишите, пожалуйста.
Важный момент. Не знаю уж почему, но AMS1117 крайне капризно относится к качеству соединений. Контакты должны быть надежны. Лучше — пропаяны. Иначе он на тестах выдает 3.3В, но под нагрузкой не выдает ничего.
Я выбрал модель 07, поскольку у нее отличный металлический экран, который работает как защита от наводок, механических воздействий и как радиатор. Последнее обеспечивает разницу между сгоревшим модулем и просто нагревшимся. Кроме того, есть гнездо под внешнюю антенну.
Чтобы чип запустился нужно соединить VCC и CH_P через резистор 10кОм. Если такого нет, то сгодится любой из диапазона 1-20кОм. Кроме того, конкретно модель 07 еще требует, чтобы GPIO15 (самый ближний к GND) был «на земле» (этого на картинке не видно, потому что соединение с другой стороны).
Теперь берем переходник USB-UART, переключаем его на 3.3В и подключаем RX к TX, TX к RX и GND к «земле» (у меня без этого передача нестабильна). Если вы не можете переключить на 3.3В, то можно использовать простейший резисторный делитель напряжения: соедините ESP RX с TX переходника через сопротивление в 1кОм, а ESP RX с «землей» через 2кОм. Существует масса более сложных и более надежных способов связать 3.3В и 5В, но в данном случае и так сойдет.
И соединяемся на скорости 9600 по нужному COM-порту (можно посмотреть в диспетчере устройств).
Я использую SecureCRT, Putty тоже подойдет, а ценители Линукса и так знают, что делать и где смотреть.
(AT+RST перезагружает чип)
Если ничего не происходит — выключите — включите питание, если все равно ничего не происходит — проверьте соответствие TX/RX, попробуйте переставить их местами или припаять к чипу.
Иногда чип в ходе издевательств экспериментов зависает и тогда его надо обесточить, в том числе отключив и переходник (например, вытащив его из USB), поскольку чипу хватает даже поступающих крох питания, чтобы упорно тупить и не работать.
Иногда фокусы с переходником вешают USB-порт. Можно в качестве временного решения использовать другой USB-порт, но вообще лучше перезагрузить компьютер.
Иногда при этом меняется номер COM-порта. Под Linux это можно решить с помощью udev.
Если вместо текста приходит мусор, то проверьте настройки скорости. Некоторые старые чипы работают на 115200.
На старте чип нагревается, но если он реально горячий и продолжает греться — отключайте и проверяйте все соединения. Чтобы на корпус не попадало +3.3В, чтобы 5В к нему вообще никуда не приходили, чтобы «земля» переходника была соединена с «землей» чипа. Модели с металлическим экраном очень трудно сжечь (но нет ничего невозможного), а на модели без экранов жалуются, мол даже небольшая ошибка может стать последней в жизни чипа. Но это я не проверял.
Мой выбор — NodeMCU. У нее проблемы с памятью и поддержкой железа, но это многократно окупается простотой кода и легкостью отладки.
Так же потребуются NodeMCU flasher и LuaLoader (последнее — опционально, есть и другие клиенты для работы с этой прошивкой).
Выключаем чип. Подсоединяем GPIO0 к земле и включаем чип:
Если ничего не происходит и поля AP MAC/STA MAC пустые — проверьте еще раз, чтобы GPIO0 был на «земле».
Если прошивка началась, но зависла — посмотрите в закладке Log, у меня почему-то конкретно этот чип отказался прошиваться на FT232RL, но зато без проблем прошился на PL2303HX на скорости 576000. PL2303HX в указанном варианте не имеет переключения на 3.3В, чтобы им воспользоваться нужно открыть пластиковый корпус и перепаять провод с 5V на 3.3V, есть варианты с пятью выходами: 3.3, 5, TX, RX, Gnd.
Обратите внимание: STA MAC поменялся. Подозреваю, что flasher его неправильно показывал, но требуется проверка.
Для экономии сил и нервов можно взять готовый или полуготовый вариант.
Есть одноразовые адаптеры с удобной разводкой.
Есть готовые к прошивке.
Есть варианты с простенькие кит-комплекты и посложнее — ESP8266-EVB
Есть с готовым USB-адаптером — NodeMCU Development Board. Под нее даже какие-то шилды делают.
Если же вы, как и я, не слишком любите готовые решения, то рекомендую всего брать с запасом, потому что опыт, как говорят, прямо пропорционален количеству сожженных компонентов.
Update: заменил в тексте «программатор» на «переходник USB-UART» или просто «переходник». По моему опыту термин «программатор» используется чаще, но, пожалуй, «переходник USB-UART» будет точнее.
Датчик температуры esp8266 arduino
Artwork by Павел Бондаренко
ESP8266 может работать в двух режимах: в режиме интерпретатора AT-команд или в режиме самостоятельного микроконтроллера с wifi модулем. Работу ESP8266 в режиме интерпретатора AT-команд я рассматривал в предыдущей статье, эта же статья рассматривает работу ESP8266 в качестве самостоятельного микроконтроллера.
Способов программирования ESP8266 опять же два, первый — это программирование с помощью ESP8266 фреймворка для Arduino IDE, второй — это программирование через esp-open-sdk. В первом случае мы можем использовать готовые библиотеки Arduino, во втором случае вы можем положиться только на функционал SDK и свой собственный код.
В этой статье мне хотелось бы рассмотреть программирование ESP8266 с помощью ESP8266 фреймворка для Arduino IDE. Данная тема решает широкий спектр задач обеспечения радиоканалом разного рода датчиков и простых устройств управления нагрузкой.
В качестве примера в статье рассматривается пошаговое написание прошивки для температурного логера на датчиках DHT11 и DS18B20. Первый датчик используется для определения комнатной температуры и влажности, второй используется для определения уличной температуры. Я статье используется плата ModeMCU ESP8266, т.к. там есть автозагузка прошивки, но в принципе может быть использована любая другая плата на модуле ESP12E/ESP12F. Данные модули оснащены флеш-памятью на 4 мегабайта, что позволяет забыть о жёсткой оптимизации размера прошивки, когда борьба идёт за каждый байт.
При работе с ESP8266 есть выбор: либо использование его совместно с «облаками», либо собственным внешним сайтом, либо собственном сервером расположенным в интросети или автономной работой ESP826, когда веб-сервер запускается на самом ESP8266.
В данном проекте используется веб-сервер uhttpd на роутере с прошивкой OpenWRT. ESP8266 передаёт на него показания датчиков, а роутер их сохраняет и виде обычных файлов, и делает их доступными для просмотра через web-интерфейс. Можно дать новую жизнь старому смартфону или планшету настроив их на отображение таких web-страниц. Web-интерфейс универсален и может отображаться на любых браузерах любых устройств.
I. Начало работы с ESP8266 фреймворком для Arduino IDE
II. Работа с библиотекой ESP8266WIFI
III. Добавлено позже
1) Установка ESP8266 фреймворка для Arduino IDE
Домашняя страница ESP8266 фреймворка для Arduino IDE расположена на гитхабе: https://github.com/esp8266/Arduino. Там имеется небольшая инструкция по устаноке фреймворка:
Установка через менеджер плат Arduino
Начиная с версии 1.6.4, Arduino IDE позволяет устанавливать пакеты поддержки сторонних платформ через менеджер плат. Мы имеем пакеты доступные для Windows, Mac OS и Linux (для 32-бит и 64-бит).
- Установите Arduino IDE версии 1.8 или выше. Текущая версия Arduino IDE находится на сайте проекта Arduino.
- Запустите Arduino IDE и откройте через меню окно настроек (Preferences).
- Введите в поле адреса дополнительных плат менеджера строку: http://arduino.esp8266.com/stable/package_esp8266com_index.json . Вы можете указывать несколько адресов разделяя их запятыми.
- Откройте менеджер плат через: меню-> инструменты -> платы -> менеджер плат и установите платформу esp8266 (не забудьте выбрать версию вашей ESP8266-платы поле установки).
Действуя в соответствии с этой инструкцией, прописываем в настройках Arduino IDE адрес репозитория «http://arduino.esp8266.com/stable/package_esp8266com_index.json»:
В менеджере плат устанавливаем пакет поддержки плат esp8266:
После установки пакета поддержки esp8266, выставляем в настройках свою плату, в моем случае это nodemcu на модуле esp12e, а настройки платы можно оставить по умолчанию:
Теперь подключаем плату NodeMCU к компьютеру, выбираем последовательный порт в Arduino IDE, находим в примерах для ESP8266 тестовый скетч «Blink», компилируем, загружаем и наслаждаемся ровным миганием синего светодиода:
Прошивка занимает почти четверь мегабайта, а процесс прошивки занимает примерно секунд двадцать. Если вы не горите желанием написать свою реализацию TCP/IP стека, то стоит принять это как данность.
Значение константы LED_BUILTIN определенно в файле
Т.е. LED_BUILTIN это GPIO_16. Если мы хотим помигать светодиодом который установлен на модуле ESP12E, то приведем скетч к следующему виду:
2) Подключение датчика DHT11 к ESP8266
Теперь нам нужно подключить к ESP8266 несколько сенсоров чтобы впоследствии передавать данные с них через WiFi.
Для начала возьмём популярной датчик температуры и влажности DHT11. Его подключение будет выглядеть так:
Датчик имеет три рабочих пина: первый пин — питание; второй пин — вывод данных, его следует подтягивать к питанию; третий пин никуда не подключается ; четвертый пин — это земля. Для подтяжки второго пина к питанию я использовал резистор на 4.7К, но т.к. датчик не скоростной, то должны сгодиться резисторы и на 10К или даже на 47К. Датчик может питаться от 3.3 Вольт, что нас вполне устраивает.
В качестве библиотеки возьмём библиотеку от Adafruit https://github.com/adafruit/DHT-sensor-library, т.к. она универсальна и поддерживает датчики DH11, DHT22(AM2302, AM2321) и DHT21(AM2301). Правда для своей работы она требует ещё одну библиотеку: https://github.com/adafruit/Adafruit_Sensor, её тоже надо будет установить.
После установки библиотек и подключения датчика DHT11 к ESP8266, загрузим в Arduino IDE тестовый скетч:
Если всё было сделано правильно, то после компиляции и загрузки прошивки, в мониторе последовательного порта можно будет наблюдать показания датчика:
3) Подключение датчика DS18B20 к ESP8266
Вторым датчиком который мы подключим ESP8266, будет DS18B20. Схема его подключения к NodeMCU ESP8266 показана ниже:
Здесь, так же как и в случае с DHT11, Data pin подтягивается к шине питания через резистор номиналом 4.7КОм.
Для работы с датчиком DS18B20 будем использовать библиотеку OneWire: https://github.com/PaulStoffregen/OneWire/. Эта библиотека как же поддерживает несколько моделей датчиков Dallas Semiconductor, что нам только на руку.
Подключаем датчик к плате NodeMCU, скачиваем библиотеку «OneWire» и открываем пример DS18x20_Temperature.
В примере правим строку:
также можно еще скорость UART поднять до значения 115200
Если все было сделано правильно, то после компиляции примера и загрузки прошивки в микроконтроллер, мы получим следующий лог работы в мониторе последовательного порта:
4) Установка WiFi соединения
Теперь, когда у нас есть данные, которые нужно куда-то передавать, самое время разобраться с библиотекой ESP8266WIFI, с помощью которой мы будем это делать.
Библиотека ESP8266WIFI имеет схожий API c библиотекой Arduino WIFI.
- Различия заключаются в следующем (взято из http://esp8266.github.io/Arduino/versions/2.1.0-rc1/doc/libraries.html):
- Добавлен метод WiFi.mode(m), который устанавливает режим работы WiFi. Здесь m — может принимать значения: WIFI_AP, WIFI_STA, WIFI_AP_STA или WIFI_OFF.
- Добавлен метод WiFi.softAP(ssid), который переключает WiFi к режим открытой точки доступа.
- Добавлен метод WiFi.softAP(ssid, password), который переключает WiFi к режим закрытой точки доступа с защитой WPA2-PSK, где ключ/password должен быть не менее восьми символов.
- WiFi.macAddress(mac) возвращает MAC-адрес в случае режима STA, WiFi.softAPmacAddress(mac) тоже самое в случае режима AP.
- WiFi.localIP() возвращает локальный IP-адрес в случае режима STA, WiFi.softAPIP() тоже самое в случае режима AP.
- WiFi.printDiag(Serial) печать через UART диагностической информации.
- Класс WiFiUDP реализует отправку и приём широковещательных multicast пакетов в STA режиме. При отправке пакетов, метод udp.beginPacket(addr, port)заменяется на udp.beginPacketMulticast(addr, port, WiFi.localIP()). class supports sending and receiving multicast packets on STA interface. При приёме пакетов, udp.beginPacket(addr, port) заменяется на udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port). Вы можете использовать udp.destinationIP() для задания multicast или unicast адреса.
Опираясь на эту информацию, начинаем писать код.
В составе библиотеки ESP8266WIFI имеется 17 примеров, среди которых имеется пример для сканирования доступных точек доступа: WIFIScan. Я переписал его на свой манер:
Результат работы программы выглядит так:
Действие программы соответствует AT-команде CWLAP, её можно свернуть в функцию с названием, скажем list_wifi(). На базе этой функции можно написать другую, которая будет искать определенную точку доступа. Можно ее будет также наделить полезным свойством, возвращать в случае обнаружения заданной точки доступа уровень ее сигнала rssi. Т.о. получим функцию двойного назначения get_rssi():
Дело осталось за малым, установить соединение с точной доступа. У меня это получилось так:
5) Использование режима энергосбережения DeepSleep
Теперь вместо задержки на функции delay() будем посылать ESP8266 в режим энергосбережения. Для этого нам нужно будет соединить выводы D0 и RST:
После этого, заменим в главном цикле стоку delay(5000) на ESP.deepSleep(3e7), которая отправит в ESP8266 в режим энергосбережения. Параметр «3e7» означает 3*10^7 микросекунд, т.е. тридцать секунд.
Лог работы программы будет выглядеть теперь так:
Здесь непечатные символы, это отладочное сообщение при выходе ESP8266 из режима энергосбережения.
Для более корректной работы, мы можем поменять алгоритм таким образом: 1)пусть в начале главного цикла сначала устанавливается WiFi соединение, 2) потом путь передаются данные, 3) после этого WiFi соединение разрывается, и ESP8266 уходит в режим энергосбережения.
6) Класс WiFiClient, получение web-страницы от сервера на OpenWRT и отправка данных через GET запрос
Теперь нужно научиться скачивать что-либо с web-сервера. Так же как и в предыдущей статье , в качестве web-сервера я использовал uhttpd-сервер установленный на роутере с прошивкой OpenWRT.
Класс WiFiCliet реализует установку TCP соединения с сервером. Демонстрационный пример его использования можно найти здесь: Client — ESP8266 Arduino Core 2.4.0 documentation. Я адаптировал этот пример под свой случай, и в итоге получилось так:
Результат работы программы выглядит так:
Для контроля можно взглянуть на дамп соединения в Wireshark:
Как видно, соединение осуществляется без ошибок. Красная строчка показывает закрытие соединения клиентом, с помощью вызова WiFi.disconnect().
Теперь аналогично предыдущей статье: Отправка данных от ESP8266 на web-сервер OpenWRT через GET запрос, мы можем отправлять на веб-сервер свои данные через GET-запрос.
Изменим в программе строку:
После чего заново компилируем и перепрошиваем esp8266. Смотрим на результат работы программы:
Как видно, данные успешно уходят на сервер.
7) Отправка на web-сервер данных с датчика DHT11 через GET запрос
Теперь нам нужно добавить к получению данных с датчика DHT11, отправку их на web-сервер через GET-запрос, как это делалось в предыдущей статье: Отправка данных от ESP8266 на web-сервер OpenWRT через GET запрос.
Программа в данном случае получается такой:
Для приёма данных, на стороне сервера нужно будет добавить cgi скрипт sensors.cgi следующего содержания:
Данный скрипт записывает полученные показания датчиков в файлы вида: ‘/site/sensors/»дата»/log.txt’. Файлы автоматически разбиваются по дням. Формат файлов выглядит так:
8) Добавление датчика DS18B20
Теперь нужно добавить опрос датчика DS18B20, и передачу его данных на web-сервер. Для этого я добавил в программу код из примера «DS18x20_Temperature» библиотеки OneWire. Этот пример поддерживает датчики: DS18S20, DS18B20, DS1822. Я не стал его упрощать затачивая конкретно под свой DS18B20, а оставил как есть:
Также немного придётся поправить cgi скрипт для приёма и записи показаний датчика DS18B20:
Теперь показания датчиков выглядят следующим образом:
Здесь ds18b20 снимает показания по одну сторону окна, а dht11 — по другую.
9) Вывод показаний датчиков через веб-интерфейс
Теперь нам нужно реализовать вывод данных через веб-интерфейс. Для этого напишем два CGI скрипта. Первый будет выводить лог измерений за текущие сутки, а второй будет выводить текущие значения. К сожалению я не обнаружил в uhttpd сервере поддержки SSI, поэтому генерацию html кода пришлось полностью реализовывать через шелл-скрипы.
GCI скрипт для вывода лога измерений получился таким:
Он довольно простой. Второй скрипт будет поинтереснее:
По желанию еще можно добавить JavaScript для автоматического обновления содержимого страницы.
Результат работы последнего скрипта на экране мобильника выглядит так:
В заключение хочу ещё добавить, что нужно внимательно отнестись к установке датчика уличной температуры. Он должен быть защищён от ветра и прямого солнечного света. Также он не должен напрямую соприкасаться со стеной или окном жилого дома. По моим наблюдениям, расстояние в 10см от стены дома достаточно для корректных показаний.
10) Второй WiFi термометр на датчике AM2320 (добавлено 26.05.19г)
Спустя полгода после изготовления термометра, должен сказать, что он получился довольно удачным. Это очень удобно, проснувшись утром взять смартфон, и тут же посмотреть какая температура сегодня за окном. Не нужно подходить к замороженому окну и пытаться разглядеть что-то за замороженым окном в темноте.
Теперь же, с приближением лета, возникла необходимость в изготовлении второго термометра. Для чего вам может понадобиться второй уличный термометр? Если у вас окна выходят на север, то вы можете не волноваться за результаты показаний термометра, он скорее-всего будет всегда казать температуру приближенную к реальной. Если же у вас все окна выходят на юг, то даже если вы будете как-то пытаться экранировать сенсор, солнце все равно будет засвечивать его, и показания «поплывут». Если же у вас, как и у меня окна, выходят на восток и запад, то большую часть года вполне можно обойтись термометром на восточном окне. Однако летом, как только встает солнце мой спрятанный под карнизом DS18B20 начинает показывать температуру кипения хлорного ангидрида, что для земной атмосферы несколько ненормально.
К счастью, имеется второе окно на западной стороне на которое можно повесить дополнительный WiFi-термометр. Делать еще один термометр на DS18B20 мне было не интересно, поэтому был куплен датчик AM2320 который кроме температуры еще измеряет и относительную влажность воздуха. Согласно даташиту на датчик: «Digital Temperature and Humidity Sensor AM2320 Product Manual», диапазон измеряемой температуры датчика от -40℃ до +80 ℃, с погрешностью в полградуса. Влажность же он измеряет во всем диапазоне с погрешностью +/- 3 %RH. Датчик может питаться от 3 и 5 Вольт, и может работать на I 2 C протоколе или однопроводному протоколу, наподобие DHT11(не путать с 1-wire).
Я буду использовать I 2 C интерфейс, на ESP12E/ESP12F он расположен на GPIO4 (SDA) и GPIO5 (SCL). На NodeMCU это соответственно выводы D2 и D1:
Подключается датчик к NodeMCU таким образом:
Подтягивающие резисторы на линии SDA и SDL ставить не надо, они есть в самом датчике. Так же как и в случае с DHT11, для работы с датчиком нам понадобится библиотека https://github.com/adafruit/Adafruit_Sensor. Кроме этого, понадобится библиотека непосредствено работающая с AM2320 https://github.com/adafruit/Adafruit_AM2320. Последняя содержит скетч для проверки работы датчика:
После компиляции скетча и прошивки NodeMCU, в окне терминала мы должны увидеть лог работы:
Остальное — дело техники. Действуя по аналогии с датчиком DHT11, напишем скетч с соединением с точкой доступа, и уходом в спящий режим:
В терминале должен пойти лог такого вида:
Теперь на роутере напишем CGI-скрипт «/site/cgi-bin/am2320.cgi» для приема и сохранения результатов измерений датчика:
Осталось привести скетч ESP8266 к окончательному рабочему виду:
Для отображения данных с двух датчиков, скрипт temperature.cgi нужно будет привести, например, к такому виду:
Выглядит гадко, но это работает. Итоговый результат на экране смартфона:
В заключение хочу немного сказать об автономном режиме работы ESP8266, т.е. режиме работы от аккумулятора. Мне пока удалось добиться беспрерывной работы всего лишь двое суток. НО. У меня довольно «слабый» аккумулятор. Это одна батарея 18650, сама обычная с али. Ее фактическая емкость где-то 500 или 600 мА. Далее у меня не самая эффективная цепь питания. C батареи питание идет на повышающий до 6 Вольт DC-DC преобразователь. Затем питание проходит через понижающий до 3.3 Вольт линейный преобразователь ams1117-3.3. В итоге, я пока имею только двое суток автономной работы. Work in progress, как говорится.