ESP8266:Примеры/Отображение температуры и влажности на веб-странице при помощи прошивки NodeMCU
Отображение температуры и влажности на веб-странице при помощи прошивки NodeMCU
В этом руководстве мы создадим при помощи ESP8266 веб-сервер, доступ к которому можно будет получить с любого устройства с браузером. Этот веб-сервер будет обслуживать страницу, показывающую текущие температуру и влажность. Для считывания этих показателей мы воспользуемся датчиком DHT11.
Необходимое оборудование
- Плата ESP8266 - 1шт.
- Датчик температуры и влажности DHT11 - 1шт.
- Резистор на 4,7 кОм - 1шт.
- Макетная плата - 1шт.
- Провода перемычки.
Справочная информация
Основы программирования на Lua
Это скриптовый язык программирования, написанный на C. Разработка этого проекта началась в 1993 году силами Роберту Иерузалимски, Луиша Энрике де Фигейреду и Валдемара Келе, работавшими тогда в подразделении Tecgraf при Католическом университете Рио-де-Жанейро.
Более подробно об этом языке программирования можно почитать в «Википедии».
Прошивка NodeMCU для ESP8266 основана на Lua, поэтому если вы хотите писать собственные скрипты для ESP8266, вам важно знать основы этого языка.
Переменные
Переменные в языке Lua не делятся по типу данных, но делятся по области видимости. Это значит, что переменные в Lua могут быть глобальными или локальными.
- Глобальные переменные. Все переменные по умолчанию считаются глобальными (если в коде специально не задано, что они локальные).
pin = 3 test = "It works!"
- Локальные переменные. Если переменная задана локальной, область ее видимости будет ограничена лишь ее функцией.
local pin = 3 local test = "It works!"
- Поля таблиц. Это особый тип переменных, в которых может храниться все, за исключением «nil» (мы это затрагивать не будем).
Типы данных (типы значений)
Lua – это язык с динамической типизацией, поэтому у переменных нет типов данных. Типы данных есть только у значений. Значения могут храниться в переменных, передаваться в виде параметров и возвращаться в виде результатов.
В таблице ниже показаны типы данных для значений в языке Lua.
Тип значения | Описание |
---|---|
Строка (string) | Массив символов |
Число (number) | Действительное (двойной точности с плавающей запятой) число |
Булево значение (boolean) | Значение «true» или «false». Как правило, используется для проверки выполнения условий |
Функция (function) | Функция, написанная на Lua |
Неопределенное значение (nil) | В такой переменной не хранится никаких данных |
Таблица (table), пользовательские данные (userdata) и поток (thread) | Эти три типа данных мы затрагивать не будем |
Вот примеры некоторых из этих типов значений:
print(type("Hello world!")) –- строка
print(type(7)) -- число
print(type(true)) -- булево значение
print(type(print)) -- функция
print(type(nil)) -- неопределенное значение
Комментарии
Комментарии – это просто текст, в котором программист объясняет, как работает его код. Если какой-то фрагмент кода помечен как комментарий, то ESP-модуль проигнорирует его и не будет обрабатывать. Комментарии начинаются с двух тире («--»). Вот два типа комментариев:
- Однострочные комментарии:
print("Hello World!") –- комментарий в одну строчку
- Многострочные комментарии:
--[[ print("Hello World!") – это многострочный комментарий --]]
Операторы
Оператор – это символ, который говорит интерпретатору выполнить определенное математическое или логическое действие. В язык Lua встроено много операторов разных типов:
- Арифметические операторы;
- Операторы сравнения;
- Логические операторы;
- Прочие операторы;
Читая таблицы и примеры ниже, представьте, что имеете дело с двумя переменными: «А», в которой хранится значение «1», и «B», в которой хранится значение «2».
A = 1
B = 2
Арифметические операторы
Оператор | Пример | Результат |
---|---|---|
+ | A + B | 3 |
- | A - B | -1 |
* | A * B | 2 |
/ | B / A | 2 |
% | B % A | 0 |
^ | B^2 | 4 |
- | -A | -1 |
Операторы сравнения
Оператор | Пример | Результат |
---|---|---|
== | (A == B) | false |
~= | (A ~= B) | true |
> | (A > B) | false |
< | (A < B) | true |
>= | (A >= B) | false |
<= | (A <= B) | true |
Логические операторы
Оператор | Пример | Результат |
---|---|---|
and (и) | (A and B) | false |
or (или) | (A or B) | true |
not (не) | !(A and B) | true |
Оператор конкатенации
Теперь представьте, что у нас две новые переменные:
a = "Hello!"
b = "World!"
Оператор | Пример | Результат |
---|---|---|
.. | a..b | "Hello World!" |
Циклы
Цикл позволяет выполнить блок кода несколько раз, пока выполняется заданное условие. Во фрагменте кода ниже – пока значением в переменной «boolean_value» является «true».
-- цикл while
while boolean_value
do
-- код будет выполняться, пока в «boolean_value» будет «true»
end
-- и цикл for
for min, max, increment
do
-- код будет выполняться, пока не будет достигнуто макс. значение
end
Операторы if… else
Операторы if... else (т.е. «если... иначе») – один из самых важных инструментов для управления программой. Они используются следующим образом:
if boolean_value then
-- если в переменной «boolean_value» значение «true»
else
-- если в переменной «boolean_value» значение «false»
end
Названия этих операторов говорят сами за себя. Если выполнено условие «boolean_value=true», то программа выполнит код, идущий после «if». Но если условием является «boolean_value=false», то программа выполнит код, идущий после «else».
Функции
Функции – отличный способ организации кода. Если вы хотите сделать в программе что-либо несколько раз, вам необязательно по несколько раз прописывать этот код. Можно просто создать отдельную функцию, содержащую этот код, а затем вызывать ее, когда вам нужно.
Ниже показано, как создать новую функцию, принимающую один параметр (температуру в градусах Кельвина) и преобразующую это значение в градусы Цельсия и Фаренгейта.
function displayTemperature(kelvin)
celsius = kelvin – 273.15
print("Temperature in Celsius is: ", celsius)
fahrenheit = (celsius*9/5+32)
print("Temperature in Fahrenheit is: ", fahrenheit)
end
k = 294 –- температура в градусах Кельвина
displayTemperature(k) –- эта строчка вызывает функцию, созданную выше
Как обращаться к контактам
В таблице ниже показано, как номер контакта ESP8266 в Lua-коде соотносится с его GPIO-номером. У платы ESP-01 только два контакта: GPIO0 и GPIO2.
Номер контакта в Lua-коде | GPIO-номер контакта |
---|---|
0 [*] | GPIO16 |
1 | GPIO5 |
2 | GPIO4 |
3 | GPIO0 |
4 | GPIO2 |
5 | GPIO14 |
6 | GPIO12 |
7 | GPIO13 |
8 | GPIO15 |
9 | GPIO3 |
10 | GPIO1 |
11 | GPIO9 |
12 | GPIO10 |
Использование датчика температуры и влажности DHT11
Датчики DHT – это относительно недорогие датчики для измерения температуры и влажности.
Внутри этого датчика есть чип, который выполняет аналогово-цифровое преобразование данных, выдавая в итоге цифровые данные о температуре и влажности.
Эти сигналы очень легко считываются любым микроконтроллером (MCU).
![](/ruwiki/images/b/bf/Mcu_to_dht11_scheme.png)
Характеристики DHT11
- Абсолютная погрешность: ±5%
- Воспроизводимость результатов: ±1%
- Долговременность стабильность измерений: ±1% в год
- Цена: между 1 и 5 долларами
![](/ruwiki/images/b/bb/Dht11_pins_1.jpg)
Контакты
- VCC (3.3 вольта)
- Вывод данных
- Не подключен
- GND
Код для загрузки
-- Rui Santos
-- Complete project details at http://randomnerdtutorials.com
wifi.setmode(wifi.STATION)
wifi.sta.config("YOUR_NETWORK_NAME","YOUR_NETWORK_PASSWORD")
tmr.delay(5000)
print(wifi.sta.getip())
pin = 1
bimb = 1
fare = 0
fare_dec = 0
--Read DHT Sensor
function ReadDHT11()
status, temp, humi, temp_dec, humi_dec = dht.read(pin)
if status == dht.OK then
print(string.format("DHT Temperature:%d.%03d;Humidity:%d.%03d\r\n",
math.floor(temp),
temp_dec,
math.floor(humi),
humi_dec
))
fare = (9 * math.floor(temp) / 5) + 32
fare_dec = (9 * temp / 5) % 10
elseif status == dht.ERROR_CHECKSUM then
print( "DHT Checksum error." )
elseif status == dht.ERROR_TIMEOUT then
print( "DHT timed out." )
end
end
ReadDHT11()
tmr.alarm(1,5000, 1, function() ReadDHT11() bimb=bimb+1 if bimb==5 then bimb=0 wifi.sta.connect() print("Reconnect")end end)
srv=net.createServer(net.TCP) srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
--print(payload) -- for debugging only
--generates HTML web site
conn:send('HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nCache-Control: private, no-store\r\n\r\n\
<!DOCTYPE HTML>\
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head>\
<meta http-equiv="X-UA-Compatible" content="IE=edge">\
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">\
<meta http-equiv="refresh" content="6">\
</head><div class="container">\
<h1>Sensor Data</h1></br><div class="row">\
<div class="col-md-4"><div class="panel panel-primary"><div class="panel-heading"><h3 class="panel-title">Humidity</h3>\
</div><div class="panel-body">\
<div class="form-group form-group-lg"><input type="text" class="form-control" value="'..math.floor(humi)..'.'..humi_dec..' %">\
</div></div></div></div>\
<div class="col-md-4"><div class="panel panel-info"><div class="panel-heading"><h3 class="panel-title">Temperature</h3>\
</div><div class="panel-body">\
<div class="form-group form-group-lg"><input type="text" class="form-control" value="'..math.floor(temp)..'.'..temp_dec..' deg C">\
<input type="text" class="form-control" value="'..fare..'.'..fare_dec..' deg F">\
</div></div></div></div></div></div></html>')
conn:on("sent",function(conn) conn:close() end)
end)
end)
Как работает этот скрипт
Код начинается с переключения ESP8266 в режим станции. Затем мы задаем SSID и пароль WiFi-сети, к которой подключаемся. Соответственно, вам нужно будет заменить параметры "YOUR_NETWORK_NAME" и "YOUR_NETWORK_PASSWORD" на собственные, чтобы ESP8266 могла подключиться к вашей WiFi-сети.
Затем при помощи функции tmr.delay(5000) задается 5-секундная пауза. Это дает ESP8266 время для подключения к сети.
В следующей строчке функция print() печатает IP-адрес ESP8266 в окне Output в IDE ESPlorer (этот IP-адрес понадобится вам, чтобы подключиться к веб-серверу).
wifi.setmode(wifi.STATION)
wifi.sta.config("YOUR_NETWORK_NAME","YOUR_NETWORK_PASSWORD")
tmr.delay(5000)
print(wifi.sta.getip())
Затем задаем контакт, к которому подключен DHT11. В данном случае это «pin = 1», что означает контакт GPIO5. Также создаем еще 3 переменные для хранения данных.
pin = 1
bimb = 1
fare = 0
fare_dec = 0
Затем создаем функцию с говорящим названием ReadDHT11(). Она считывает с датчика DHT11 данные о температуре и влажности, а затем сохраняет их в правильные переменные. Она также печатает эти данные в окно Output в IDE ESPlorer.
function ReadDHT11()
status, temp, humi, temp_dec, humi_dec = dht.read(pin)
if status == dht.OK then
print(string.format("DHT Temperature:%d.%03d;Humidity:%d.%03d\r\n",
math.floor(temp),
temp_dec,
math.floor(humi),
humi_dec
))
fare = (9 * math.floor(temp) / 5) + 32
fare_dec = (9 * temp / 5) % 10
elseif status == dht.ERROR_CHECKSUM then
print( "DHT Checksum error." ) -- "Ошибка контрольной суммы"
elseif status == dht.ERROR_TIMEOUT then
print( "DHT timed out." ) -- "Таймаут"
end
end
ReadDHT11()
Нам также нужно создать функцию tmr.alarm(), которая будет запускать функцию ReadDHT11() каждые 5 секунд. При каждом вызове она считывает текущие данные о температуре и влажности. Далее мы создаем объект веб-сервера на порте 80 и вызываем функцию conn:send().
tmr.alarm(1,5000, 1, function() ReadDHT11() bimb=bimb+1 if bimb==5 then bimb=0 wifi.sta.connect() print("Reconnect")end end)
srv=net.createServer(net.TCP) srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
--print(payload) – только для отладки
-- генерирует HTML-страницу
conn:send()
conn:on("sent",function(conn) conn:close() end)
end)
end)
Внутри функции conn:send() мы пишем данные HTML-страницы (см. код ниже). Это простая веб-страница, использующая фреймворк Bootstrap. Более подробно о Bootstrap можно почитать тут.
conn:send('HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nCache-Control: private, no-store\r\n\r\n\
<!DOCTYPE HTML>\
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"></head>\
<meta http-equiv="X-UA-Compatible" content="IE=edge">\
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">\
<meta http-equiv="refresh" content="6">\
</head><div class="container">\
<h1>Sensor Data</h1></br><div class="row">\
<div class="col-md-4"><div class="panel panel-primary"><div class="panel-heading"><h3 class="panel-title">Humidity</h3>\
</div><div class="panel-body">\
<div class="form-group form-group-lg"><input type="text" class="form-control" value="'..math.floor(humi)..'.'..humi_dec..' %">\
</div></div></div></div>\
<div class="col-md-4"><div class="panel panel-info"><div class="panel-heading"><h3 class="panel-title">Temperature</h3>\
</div><div class="panel-body">\
<div class="form-group form-group-lg"><input type="text" class="form-control" value="'..math.floor(temp)..'.'..temp_dec..' deg C">\
<input type="text" class="form-control" value="'..fare..'.'..fare_dec..' deg F">\
</div></div></div></div></div></div></html>')
Этот код создает симпатичную страницу, показывающую данные о температуре и влажности, а также способную адаптироваться под экраны мобильных устройств.
Загружаем скрипт «init.lua»
Чтобы загрузить этот Lua-скрипт на ESP8266, проделайте следующее:
- Подключите ESP8266 (напрямую или через FTDI-программатор) к ПК
- Выберите COM-порт, к которому подключен ESP8266
- Нажмите на кнопку «Open/Close»
- Выберите вкладку «NodeMCU+MicroPython»
- Создайте новый файл под названием «init.lua»
- Нажмите на кнопку «Save to ESP»
Кроме того, в окне Output будут напечатаны команды, отсылаемые ESP8266.
![](/ruwiki/images/2/2a/Esp8266_nodemcu_lua_file_deleting.png)
Узнаем IP-адрес ESP8266
После того, как вы загрузите на ESP8266 веб-серверный Lua-скрипт, в окне Output в IDE ESPlorer должно появиться три IP-адреса.
Нам нужен самый первый IP-адрес. В моем случае это «192.168.1.70», но у вас, скорее всего, будет какой-то другой IP-адрес. Сохраните его где-нибудь, потому что чуть позднее он нам понадобится.
![](/ruwiki/images/d/d5/Esp8266_lua_-_ip_address.png)
Собираем цепь
Загрузив скрипт на ESP8266, соберите цепь, показанную ниже. Для подключения DHT11 вам также понадобится резистор номиналом 4,7 кОм или выше, который будет служить подтягивающим резистором.
![](/ruwiki/images/a/a7/ESP8266_schematics_bb_ESP8266_DHT11DHT22_6.jpg)
Подключаемся к веб-серверу
Чтобы подключиться к веб-серверу, проделайте следующее:
- Перезапустите ESP8266
- Откройте браузер
- Впишите в адресную строку браузера IP-адрес, сохраненный ранее (в моем случае это «192.168.1.70»)
В результате должна загрузиться примерно такая веб-страница:
![](/ruwiki/images/thumb/3/33/Esp8266_lua_nodemcu_dht11_web_server.jpg/640px-Esp8266_lua_nodemcu_dht11_web_server.jpg)
Клево, а? Смело пробуйте модифицировать этот Lua-скрипт и добавлять в него свои идеи. И помните, что эта веб-страница будет автоматически обновляться каждые 6 секунд.
Кроме того, эта HTML-страница способна адаптироваться под любые экраны, так что она будет хорошо выглядеть в том числе и на экране мобильного устройства.
Что дальше
Плата ESP-12E оснащена лишь одним аналоговым контактом, что очень неудобно, если вы хотите подключить к своему проекту больше одного аналогового датчика/модуля...
Как можно обойти эту проблему? Есть один вариант.
Можно настроить последовательную коммуникацию между Arduino и ESP8266 и подключить к Arduino нужные датчики.
Arduino будет делать всю черную работу, считывая данные с датчиков, а затем отправляя их по последовательному порту ESP8266. Сам ESP8266, тем временем, будет получать эти данные и показывать их на веб-странице!
Впрочем, вам нужно будет немного адаптировать некоторые фрагменты этого руководства, чтобы Arduino могла считывать данные с датчиков.
См.также
Внешние ссылки
ESP8266 AT-команды | |
---|---|
Список AT-команд | |
Базовые команды |
|
Команды для WiFi |
|
Команды для TCP/IP |
|