На этот раз решил подключить преобразователь влажности AM2302. Кроме влажности он выдает данные и по-температуре. Написание кода не составило труда, т.к. библиотека для датчика влажности, как и для датчика температуры из прошлой статьи, встроена в прошивку (см. часть 1). И нам остается только запрашивать готовые данные, минуя написание кода по их получению из самого преобразователя.
Как обычно, код состоит из 4 файлов. Когда-нибудь руки все же дойдут до написания кода для перепрошивки ESP8266 по-воздуху, но пока будем только мониторить данные )))
Код файла init.lua (автозагрузка модуля):
dofile("config.lua") -- подгружаем файл config.lua dofile("main.lua") -- подгружаем основной файл программы main.lua
Код файла config.lua (файл общих настроек):
-- Для дальнейшего удобства лучше хранить данные в таблице, а не в переменной. -- При изменении какого-либо значения по-воздуху POST-запросом -- удобнее будет перезаписывать данные. -- Для редактирования в ESPlorer тип значений может быть любой config = {} config.LanSSID = "ssid" -- название wifi-сети config.LanPWD = "password" -- пароль wifi-сети config.LanServer = "192.168.1.15" -- IP-адрес сервера с установленной системой MajorDoMo
Код файла main.lua (основной файл выполнения программы):
--Конфигурируем чип как клиента, присоединяемся к существующей сети WiFi --Присоединяемся к сети WiFi --При неудачном соединении создаем свою точку доступа 192.168.1.200 --При удачном - поднимаем веб-сервер, выводим список доступных дочек доступа --Опрашиваем датчик HC-SR501 каждые 500 мс connect=0 --статус присоединеия к существующей сети WiFi -- поднимаем точку доступа function setSOFTAP() local cfg={} cfg.ssid="ApESP8266" cfg.pwd="password" wifi.setmode(wifi.SOFTAP) wifi.ap.config(cfg) print(wifi.ap.getip()) end -- Проверка на соединение с точкой доступа (проверка получения IP) function getConnect() if wifi.sta.getip() ~= nil then -- если IP-адрес получен (не равен NIL) connect = 1 -- ставим статус получения адреса print("IP-адрес получен: "..wifi.sta.getip()) startWork() -- запускаем функцию начала цикла работы else connect = 0 print("IP-адрес не получен, поднимаем точку доступа") setSOFTAP() -- если присоединиться не удалось, поднимаем свою точку доступа end end -- Конфигурируем чип как клиента, присоединяемся к существующей сети WiFi -- Заводим таймер на 5 сек. Если по прошествии этого времени не получили IP? -- то поднимаем свою точку доступа, свой веб-сервер wifi.setmode(wifi.STATION) -- конфигурируем чип как клиент wifi.sta.autoconnect(1) -- включаем автоприсоединение к сети wifi.sta.config(config.LanSSID, config.LanPWD, true) -- присоединяемся к сети, сохраняем настройки конфигурации во FLASH tmr.alarm(0, 5000, tmr.ALARM_SINGLE, getConnect) --заводим таймер на 5 секунд function startWork() -- поднимаем сервер на 80 порту с таймаутом 30 сек srv = net.createServer(net.TCP, 30) -- формируем ответ из нескольких строк клиенту и отправляем function receiver(sck, data) --print(data) --отправляем данные о подключении на UART local response = {} response[#response + 1] = "<html><body style=\"font-family: Verdana, Arial, Helvetica, sans-serif;\"><center>" response[#response + 1] = "<h1>Ap SmartHome</h1> <br/>Температура: "..AM2302_READ_T().." °C" response[#response + 1] = "<br/>Влажность: "..AM2302_READ_H().." %" response[#response + 1] = "</center></body></html>" -- отправляем и удаляем первый элемент из таблицы response, пока не отправим все local function send(localSocket) if #response > 0 then --пока длина таблицы response не равна нулю localSocket:send(table.remove(response, 1)) else localSocket:close() -- если все отправили - закрываем сокет response = nil -- удаляем переменную "response" end end -- triggers the send() function again once the first chunk of data was sent sck:on("sent", send) --если отправили посылку - отправляем еще раз send(sck) end -- Мониторим 80 порт. Если есть запрос от клиента - выполняем функцию "receiver" if srv then srv:listen(80, function(conn) conn:on("receive", receiver) end) end local function am2302() print("Память:"..node.heap()) dofile("AM2302.lua") print("DHT Temperature:"..am2302_data.t.."; Humidity:"..am2302_data.h) -- Отправка данных о температуре и влажности -- Т.к. за 1 раз можно установить только 1 свойство, то устанавливаем -- 2 соединения по очереди, в каждом меняем нужную переменную srv = net.createConnection(net.TCP, 0) -- создаем новое TCP-соединение srv:connect(81,"192.168.1.15") -- коннектимся к серверу с установленным MajorDoMo srv:on("connection", function(sck, c) -- если соединение установлено, отправляем данные на сервер sck:send("GET /objects/?object=humidityKitchen&op=set&p=humidity&v="..AM2302_READ_H().." HTTP/1.1\r\nHost: 192.168.1.15\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n") end) srv = net.createConnection(net.TCP, 0) -- создаем новое TCP-соединение srv:connect(81,"192.168.1.15") -- коннектимся к серверу с установленным MajorDoMo srv:on("connection", function(sck, c) -- если соединение установлено, отправляем данные на сервер sck:send("GET /objects/?object=humidityKitchen&op=set&p=temperature&v="..AM2302_READ_T().." HTTP/1.1\r\nHost: 192.168.1.15\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n") end) collectgarbage() tmr.wdclr() end -- Таймер на опрос am2302 каждые 5 секунд tmr.alarm(0, 5000, tmr.ALARM_AUTO, am2302) end
Небольшой особенностью является то, что датчик выдает данные и по-влажности, и по-температуре. Т.е. нам придется устанавливать 2 свойства в 1 объекте. А т.к. за 1 раз можно установить 2 свойства, мы просто создаем подключение к МДМ 2 раза, и передает данные о температуре и влажности по-отдельности. Можно сделать это циклом FOR, но я решил просто продублировать код для наглядности.
Код файла AM2302.lua (библиотека преобразователя AM2302. Основная функция — чтение влажности и температуры):
am2302_data = {} --Глобальная таблица данных датчика DS18B20 am2302_data.t=0 --температура am2302_data.h=0 --ID датчика DS18B20 function am2302_start() local pin = 1 local status, temp, humi, temp_dec, humi_dec = dht.read(pin) if status == dht.OK then am2302_data.t=temp.."."..temp_dec am2302_data.h=humi.."."..humi_dec elseif status == dht.ERROR_CHECKSUM then print( "Неверная контрольная сумма" ) elseif status == dht.ERROR_TIMEOUT then print( "DHT timed out" ) end collectgarbage() end function AM2302_READ_T() return am2302_data.t end function AM2302_READ_H() return am2302_data.h end am2302_start() -- запускаем 1 цикл опроса датчика
Опрос датчика влажности происходит каждые 5000 мс. По окончании измерения создаем соединение к серверу с установленной системой МДМ, и отправляем GET-запросом данные о температуре и влажности, где они и сохраняются. Также показания выводятся в UART.
При заходе на веб-сервер ESP8266 получаем температуру и влажность на экран браузера
Ну и непосредственно отправка данных на МДМ. Опять создаем дочерний класс HumiditySensor от класса ESP8266
Добавляем 2 свойства: humidity и temperature
Общий вид свойств класса выглядит так
Теперь можно создать объект класса HumiditySensor, т.е. физическое устройство. Как обычно, размещаем на кухне ))))
Сохраняем. Все, теперь значения свойств будут обновляться каждые 5 секунд. Повесим их на главный экран. Создадим новый элемент меню управления (Панель управления -> Объекты -> Меню управления).
Наблюдаем на главном экране:
Ну и для наглядности выведем график. Создаем новый элемент Charts (Панель управления -> Объекты -> Меню управления -> Charts). И добавляем в него новый график, и два свойства — значения и влажности. Сохраняемся, наблюдаем красоту )))