Многофункциональный датчик температуры-влажности на ESP8266 или еще один шаг к «интернету вещей»

в 9:58, , рубрики: diy или сделай сам, esp8266, nodeMCU, программирование микроконтроллеров, Разработка для интернета вещей, метки: ,

Дисклеймер: данная статья может содержать ошибки, поскольку я не так давно работаю с модулем ESP8266 и еще не до конца понимаю многие архитектурных аспекты данного устройства.

Сегодня практически в любом доме есть Wi-Fi роутер и было бы недальновидно не воспользоваться этим устройством для домашней автоматизации, тем более что сегодня на рынке есть все доступное оборудование для реализации любых идей. Ниже будет представлен вариант создания небольшого электронного устройства, являющегося платформой для построения различных датчиков/исполнительных механизмов на основе Wi-Fi модуля — ESP8266.

image

Данный модуль хорошо описан здесь, здесь, а на этом сайте вы найдете вообще все, что знает человечество о модуле ESP8266.

Итак, что должно «уметь» устройство:

  • Получать данные с датчика влажности/температуры DHT22;
  • Управлять твердотельным реле (например SSR-25 DA);
  • Подключаться к Wi-Fi роутеру с заданным логином и паролем;
  • Передавать и получать данные через MQTT брокер;
  • Подключаться по USB для отладки и прошивки.

Схема устройства:

image

Модифкаций модуля ESP8266 очень много (варианты здесь), но, в принципе, отличаются они только размерами, типом антенны и количеством доступных портов ввода-вывода. Я использовал модуль ESP8266 ESP-01:

image

У него всего два порта (не считая USART) — GPIO0, GPIO2, но для моих целей достаточно, один порт — для датчика и второй — для управления нагрузкой.

Интерфейс USB реализуется USB-USART преобразователем CH340G.

image

Здесь описанно его подключение к 3.3 и 5В логике. Микросхема очень дешевая и удобная в использовании. Из обвязки только кварцевый генератор на 12MHz и пара конденсаторов. В итоге у вас с одной стороны USART, а с другой — USB. На PC устройство отображается как виртуальный последовательный порт.

Для управления нагрузкой я использовал пару транзисторных ключей. Почему так — спросит прожженный электронщик внимательный читатель. Все дело в том, что напряжение питания может быть разным, а мне хотелось, чтобы реле управлялось напряжением=напряжению питания. При использовании pnp транзистора, ток эмиттера (при напряжении питания > напряжения модуля ESP8266) пойдет в модуль, что совсем не хорошо. Использовать только npn транзистор я не мог, так как тогда порт GPIO0 все время будет подтянут к минусу, а в этом случае модуль будет входить в режим программирования каждый раз, когда мы рестартим модуль. Таким образом, подключив pnp + npn транзисторы, я управляю минусом реле.

Датчик DHT22:

image

Не требует никакой дополнительной обвязки и подключается прямо к модулю ESP. Ему нужен только один порт для обмена данными(интерфейс подобный 1-wire).

Так же на схеме:

  • Перемычка JP2 — для прошивки модуля. Перемычка подтягивает GPIO0 к минусу. В рабочем режиме — разомкнута, во время прошивки — замкнута);
  • Кнопка S1 — reset модуля;
  • Разъем SV1 — подключение реле;
  • Разъем J1 — гнездо питания;
  • Разъем JP1 — micro USB мама.

Питается устройство 5 — 12В.

Теперь поговорим о программном обеспечении.

Есть такой проект NodeMCU. На мой взгляд, очень крутая штука. Небольшая ОС, которая может выполнять ваши lua-скрипты прямо на ESP8266. NodeMCU умеет работать с кучей протоколов из коробки, может поднять web сервер, создать TCP соединение…

В начале прошиваем в наш модуль NodeMCU. Инструкция по прошивке.

После того, как модуль прошит, можно загружать наши скрипты. Способов множество, но лично мне нравится утилита ESPlorer — очень удобная софтина не только для загрузки скриптов, но и для разработки, дебага скриптов.

Теперь более подробно. Нам нужно залить три скрипта:

dht22.lua - собственно модуль считывающий данные с датчика DHT22

— ***************************************************************************
— DHT22 module for ESP8266 with nodeMCU
— — Written by Javier Yanez
— but based on a script of Pigs Fly from ESP8266.com forum
— — MIT license, opensource.org/licenses/MIT
— ***************************************************************************

local moduleName =…
local M = {}
_G[moduleName] = M

local humidity
local temperature

function M.read(pin)
local checksum
local checksumTest
humidity = 0
temperature = 0
checksum = 0

— Use Markus Gritsch trick to speed up read/write on GPIO
local gpio_read = gpio.read

local bitStream = {}
for j = 1, 40, 1 do
bitStream[j] = 0
end
local bitlength = 0
— Step 1: send out start signal to DHT22
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
tmr.delay(100)
gpio.write(pin, gpio.LOW)
tmr.delay(20000)
gpio.write(pin, gpio.HIGH)
gpio.mode(pin, gpio.INPUT)

— Step 2: DHT22 send response signal
— bus will always let up eventually, don't bother with timeout
while (gpio_read(pin) == 0 ) do end
local c=0
while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
— bus will always let up eventually, don't bother with timeout
while (gpio_read(pin) == 0 ) do end
c=0
while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end

— Step 3: DHT22 send data
for j = 1, 40, 1 do
while (gpio_read(pin) == 1 and bitlength < 10 ) do
bitlength = bitlength + 1
end
bitStream[j] = bitlength
bitlength = 0
— bus will always let up eventually, don't bother with timeout
while (gpio_read(pin) == 0) do end
end

--DHT data acquired, process.
for i = 1, 16, 1 do
if (bitStream[i] > 3) then
humidity = humidity + 2 ^ (16 — i)
end
end
for i = 1, 16, 1 do
if (bitStream[i + 16] > 3) then
temperature = temperature + 2 ^ (16 — i)
end
end
for i = 1, 8, 1 do
if (bitStream[i + 32] > 3) then
checksum = checksum + 2 ^ (8 — i)
end
end

checksumTest = (bit.band(humidity, 0xFF) + bit.rshift(humidity, 8) + bit.band(temperature, 0xFF) + bit.rshift(temperature, 8))
checksumTest = bit.band(checksumTest, 0xFF)

if temperature > 0x8000 then
— convert to negative format
temperature = -(temperature — 0x8000)
end

— conditions compatible con float point and integer
if (checksumTest — checksum >= 1) or (checksum — checksumTest >= 1) then
humidity = nil
end
end

function M.getTemperature()
return temperature
end

function M.getHumidity()
return humidity
end

return M

main.lua - основной скрипт, выполняет подключение к Wi-Fi сети, получает данные, отправляет их по mqtt и управляет нагрузкой

function subscribe()
m:subscribe("/myhome/"..id.."/light",0,function(conn)print(«Subscribe success»)end)
m:on(«message»,function(conn,topic,data)
print(topic… ": "..data )
if data==«ON»then gpio.write(3, gpio.LOW)end
if data==«OFF»then gpio.write(3, gpio.HIGH)end
end)
end

function dht22_get_data()
dht22=require(«dht22»)
dht22.read(4)
local t=dht22.getTemperature()
local h=dht22.getHumidity()
if t~=nil then
t=((t-(t % 10))/10).."."..string.format("%.i",(t % 10))
else t=nil
end
if h~=nil then
h=((h-(h % 10))/10).."."..string.format("%.i",(h % 10))
else h=nil
end
dht22=nil
package.loaded[«dht22»]=nil
collectgarbage()
return t, h
end
function post_data()
t, h = dht22_get_data()
if t ~= nil then
m:publish("/myhome/"..id.."/temperature",t,0,0, function()
print(«Temperature »..t)
if h ~= nil then
m:publish("/myhome/"..id.."/humidity",h,0,0, function()print(«Humidity »..h)end)
end
end)
end
end

function init_network()
collectgarbage()
print(id)
if wifi.sta.status() ~= 5 then
print(«Reconnecting WIFI»)
wifi.setmode(wifi.STATION)
wifi.sta.config(«Login»,«password»)
wifi.sta.connect()
tmr.alarm(0,5000,0,function()init_network()end)
else
print(«IP: »..wifi.sta.getip())
print(«Connecting to MQTT server»)
tmr.alarm(0,7000,0,function()init_network()end)
if m~=nil then
m:close()
end
m = mqtt.Client(id, 120)
m:connect(«192.168.0.x»,1883,0,function(conn)
tmr.stop(0)
print(«Connected»)
subscribe()
tmr.alarm(0, 60000, 1, function() post_data() end)
m:on(«offline»,function(con)
print(«offline.Reconnecting»)
init_network()
end)
end)
end
end

gpio.mode(3, gpio.OUTPUT)
id=«esp_»..wifi.sta.getmac()
init_network()

init.lua - стартовый скрипт. Его первым запускает NodeMCU на старте.

print(«ESP8266_home_board_v_x.x»)
dofile('main.lc')

Здесь есть нюанс. К сожалению, внешней флэш памяти модуля не достаточно для загрузки NodeMCU и моих скриптов, поэтому я использую следующее «костыльное» решение: загружаю один скрипт, выполняю команду node.compile(«dht22.lua») — данная команда компилирует скрипт в «dht22.lc», в результате он занимает меньше места и во флэш памяти и в оперативной памяти, та как потом NodeMCU будет загружать его в память во время выполнения основного скрипта. Потом удаляем нескомпилированный скрипт командой file.remove («dht22.lua»). Проделываем те же манипуляции с main.lua. Последним загружаем init.lua скрипт, его уже не компилируем. Рестартим модуль.

На старте NodeMCU выполнит «init.lua» скрипт, который в свою очередь запустит «main.lua». «main.lua» скрипт будет коннектится к сети, отправлять данные в COM порт и в сеть на заданный mqtt брокер.

Более подробно по скриптам отвечу в комментариях.

Ну, вроде бы все. Если тема интересна, в следующей статье расскажу про mqtt брокер и подключение всего этого дела к Openhab.

Спасибо за внимание.

Автор: romang88

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js