воскресенье, 2 апреля 2017 г.

#ESP.Meteo с функцией альтиметра (определяем точку росы и давление)


Мы давно хотели расширить функционал нашей метеостанции ("вечного" Wi-Fi логгера) с питанием от солнечной панели и ионисторов, а также прогнозированием заморозков по методике профессора Броунова с отправкой данных в облако ThingSpeak и Twitter. Однако заказанный с AliExpress многофункциональный датчик температуры, влажности и давления видимо был отправлен продаваном улиточной почтой и получен только сейчас. Речь конечно же о бошевском сенсоре BME280 в LGA корпусе габаритами 2.5х2.5 mm. Сегодня произведем наружный монтаж сенсора (заодно сделаем ревизию как пережил зиму DHT) и модифицируем ПО метеостанции на Lua в части измерения высоты и точки росы...

Предпосылки реализации. ТТХ железа

BME280 может работать по интерфейсам I2C/SPI и имеет три режима работы – Normal, Forced, Sleep. В режиме Normal данные проходят через цифровой сглаживающий фильтр и доступны в асинхронном режиме. В режиме Forced данные отправляются по запросу, а в режиме Sleep датчик переходит в режим минимального потребления, активируя лишь драйвер для быстрого считывания (сам чип спит).


Кратко ТТХ BME280 представлено в таблице 1.

Таблица 1. ТТХ датчика BME280

Габариты платы модуля с BME280 и небольшой SMD-навеской из блокировочной емкости и подтягивающими резисторами не превышают 15х12 mm (с нашей точки зрения плату можно было и поменьше оттрассировать):


Основные команды для работы с датчиком из интерпретатора NodeMCU доступны в документации. Нам понадобятся следующие:

1. Инициализация датчика и подключение (см. 1)

Bme280.init (sda, scl, [temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter]); (1)

Где: Вывод sda - SDA, Scl - вывод SCL, (Необязательно) temp_oss - управляет избыточной выборкой данных температуры (передискретизация по умолчанию - 16x), (Optional) press_oss - управляет избыточной выборкой данных давления, humi_oss - управляет избыточной дискретизацией данных влажности, sensor_mode - управляет режимом датчика устройства, inactive_duration - управляет неактивной продолжительностью в нормальном режиме (по умолчанию неактивная продолжительность составляет 20 мс), IIR_filter - управляет постоянной времени для БИХ-фильтра (по умолчанию коэффициент фильтра равен 16), cold_start - если равен 0, то BME280 не инициализируется (полезно при ограниченных энергетических ресурсах, когда ESP глубоко спит и при пробуждении необходимо инициализировать драйвер), но не сам чип.

2. Чтение параметров из датчика (см. 2)

to,p,h,q=bme280.read(altitude); (2)

Где: to - температура воздуха, °C; p - давление воздуха, гПа; h - влажность воздуха, %; q - приведенное давление воздуха над уровнем моря, гПа.

3. Определение точки росы* по влажности и температуре окружающей среды (см. 3 и онлайн-калькулятор)
bme280.dewpoint(H, T); (3)
Где: H - влажность воздуха, %; T - температура воздуха, °C.
* Точка росы - это температура воздуха при которой водяной пар, содержащийся в нем, начинает конденсироваться в росу. Точка росы определяется относительной влажностью воздуха. Чем выше относительная влажность, тем выше точка росы и ближе к фактической температуре воздуха. Если относительная влажность составляет 100%, то точка росы совпадает с фактической температурой. 
Точку росы можно приблизительно оценить по формуле 4.

Tp=Tout-(100*(1-(H/100))/5); (4)

Где: Tp - температура точки росы, °С; Tout - температура окружающего воздуха, °С; H - влажность окружающего воздуха, %.

Известно, что при значениях точки росы выше +20 °С воздух кажется душным, а большинство людей чувствуют дискомфорт. Свыше +25 °С проявляется опасность для людей с болезнями дыхательных путей и сердца (см. таблицу 2).

Таблица 2. Влияние точки росы на восприятие человеком


Используемое ПО и оборудование

Для работы понадобится:
  1. Наша метеостанция на базе модуля ESP-12-E с StepUP DC-DC преобразователем из предыдущего цикла.
  2. Датчик BME280.
  3. Паяльник мощность не более 60 Вт.
  4. Кусачки/скальпель.
  5. Провод МГТФ 0.07 длиной около 60 см.
  6. Отвертка или шуруповерт.
  7. Ноутбук/ПК с установленным драйвером конвертора USB/UART TTL и загрузчиком LuaLoader.
  8. Программа-прошивальщик FLASH_DOWNLOAD_TOOLS_v2.4_150924.
  9. Прошивка NodeMCU dev 16 от 2017-03-30-09-22-26 с поддержкой операций с плавающей точкой.
  10. Любой конвертор USB/UART TTL (на базе PL2303/FT232RL/CH340G) для заливки прошивки NodeMCU и LUA-скриптов.
Для установки BME280 на выносную штангу (для исключения влияниях восходящих потоков воздуха) проведем ее демонтаж с целью замены DHT, после чего в трубе протянем дополнительный провод (работать с датчиком будем по интерфейсу I2C) и посадим его на клеммник. Проведем обратный монтаж и подключим датчик к метеостанции.


Схема электрическая принципиальная Wi-Fi логгера меняется незначительно (см. рисунок ниже).


Под новый датчик были задействованы GPIO14 (регистр 5) и GPIO12 (регистр 6). Напомним, что на GPIO2 по 1-Wire шине может быть дополнительно подключено до 16-ти** (см. массив в коде ниже) датчиков DS18B20 (сопротивление R8 при этом следует уменьшить до 2.2 кОм). GPIO16, генерирующий аппаратный сброс модуля A1 (Hard Restart), объединен с RST модуля и подтянут на плюс питания через сопротивление порядка 10 кОм. Вход EN модуля A1 подтянут на плюс питания, аналогично линиям ввода-вывода GPIO0, GPIO2. Для входа в режим программирования по входу GPIO0 опционально установлена кнопка S1, подтягивающая его к нулевому уровню (общему проводу). Если вы используете версию модуля ESP выше 1-й, то GPIO15 следует подключать к общему проводу. Супервизор DA2 запрещает старт модуля A1 нулевым уровнем при напряжении питания менее 2.9 В и устраняет зависание чипа ESP8266 при медленном заряде ионисторов.
** Максимальное количество полей в сервисе Thinkspeak для бесплатного акка ограничено 8-ми, соответственно передать данные более этого количества за раз вы не сможете. В коде массив реализован с запасом для 16 датчиков на шине и для отправки всех значений понадобится создать два бесплатных аккаунта с 8-ю полями и своими API-ключами доступа.
Сборка компилятора NodeMCU и прошивка

До последнего времени во всех своих проектах мы использовали бинарный образ версии 0.9.6 с поддержкой операций с плавающей точкой. Как оказалось, несмотря на поддержку даже OLED-дисплеев на базе SSD1306, данная сборка не работает с BME280. На гитхабе из свежих версий лежат только исходные коды проектов. Где взять, чтобы ничего лишнего не ставить на машине и не засорять ОС? Идем на онлайн-конструктор http://nodemcu-build.com и отмечаем следующие галочки***:


*** Ниже галочки не ставьте, только если вам захочется работать с внешней SD-картой. 
После ввода E-mail через несколько минут вам придет подтверждение и ссылка на скачивание версий NodeMCU с поддержкой и без поддержки операций с плавающей точкой. Нам понадобится с поддержкой.

Нюансы прошивки

Для перепрошивки модуля ESP можно было использовать уже знакомый ESP8266Flasher. Однако вышеозначенный онлайн-конструктор имеет одну нехорошую бяку - в прошивках не подключается TOUT (107 бит) для считывания системного напряжения, которое в скрипте метеостанции используется для мониторинга напряжения на ионисторах. Функция adc.readvdd33() будет всегда возвращать значение 65535. Для фикса подобного беспредела воспользуемся более функциональным прошивальщиком - FLASH DOWNLOAD TOOLS (не ниже версии 2.4). Поскольку используется ESP-12-E с EEPROM на борту 4 МB, то настройки будут следующие:


Для активации возможности мониторинга системного напряжения перейдем на вкладку RF InitConfig и отметим параметр TOUT_VDD_EN:


Теперь вернемся на предыдущую вкладку, выбираем номер последовательного виртуального порта на котором определился USB конвертор, жмакаем кнопку "Start" и идем "пить чай". По окончании процесса заливки можем приступать к модификации ПО метеостанции. 

Модификация ПО метеостанции

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

Функция альтиметра

Оговорим сразу, что для стационарного использования, как в случае метеостанции, данная "фича" может носить разве что справочный характер (да еще и погодозависима). Альтиметр скорее пригодится для мобильного использования и реализация его сейчас идет с расчетом на будущее и в помощь разработчикам, своего рода - must have. Расчет высоты по текущей величине давления и приведенному давлению на уровне моря реализован в NodeMCU функцией bme.altitude:

bme280.altitude(P, QNH)

Но похоже реализован через "одно место". Взглянем на пример в документации:
alt=320
-- altitude of the measurement place
bme280.init(3, 4)
P, T = bme280.baro()
-- convert measure air pressure to sea level pressure
QNH = bme280.qfe2qnh(P, alt)
-- altimeter function - calculate altitude based on current sea level pressure (QNH) and measure pressure
curAlt = bme280.altitude(P, QNH)
Задается условная высота, считывается текущее давление baro(), по высоте и давлению получаем приведенное давление на уровне моря qfeqnh() и наконец реальная высота. Так вот на выходе функции altitude() получаем всегда заданную условную высоту. Разработчики пива перепили. 

Для фикса сего бага воспользуемся классической барометрической формулой (5), характеризующей зависимость давления слоев газа от высоты и температуры окружающей среды.
Ph = Po * exp (-µ * g * h / R / T); (5)

Где: Ph - давление газа на высоте h, гПа; Po - давление газа на уровне моря, 1013.25 гПа; µ - молярная масса воздуха, 0.029 кг/моль; g - ускорение силы тяжести, 9.81 м/c^2; h - разность высот, м; R - универсальная газовая постоянная, 8.31 Дж/(моль*К); T - температура воздуха, К.


Для исключения экспоненты из (5) вынесем Po в левую часть и прологарифмируем обе части уравнения, вынесем степень за логарифм и выразим высоту (6):

Ln(Ph/Po) = Ln (exp (-µ * g * h / R / T))  h = -µ * g * Ln(Ph/Po) / R / (T+273.15);  (6)

Почти все величины из (6) константы, но вот незадача - NodeMCU не поддерживает вычисление логарифмов. Не беда, вспомним разложение функций в степенной ряд. Да это будет приближенное вычисление, а больше второго знака нам и не нужно. Для |x| < 1 функцию вида Ln (1+x) можно разложить в бесконечный ряд Тейлора (7) для n э [1; ].

Ln (1+x) = SUM (-1^(n+1)*x^n/n) → x-(x*x/2)+(x*x*x/3) -(x*x*x*x/4)+...; (7)

При этом достаточно ограничиться 3-4-мя членами ряда для тысячной точности после запятой. Обратите внимание, если соотношение давления на заданной высоте к давлению на уровне моря менее единицы (т.е. речь о высоте выше уровня моря) или более, то для сходимости ряда берем модуль разницы текущего давления с единицей. Вычисление высоты можно выразить следующим Lua-кодом: 
xx=p/1013250 -- знаменатель есть 760 мм.рт.ст.
if xx<1 then xx=xx-1 end
if xx>1 then xx=1-xx end
yy=xx-(xx*xx/2)+(xx*xx*xx/3) -(xx*xx*xx*xx/4)
alt=-100*8.31*(temp+273.15)*yy/(0.029*9.81)
alt=string.format("%d.%02d",alt/100,alt%100)
print("Altitude: "..alt)
Алгоритм работы метеостанции

Последовательность действий в скриптах следующая:

1. Создаем массив датчиков DS18B20 (до 16-ти).
2. Задаем поправку времени на наш часовой пояс UTC+2.
3. Отключаем режим автоподключения радиотракта.
4. Настраиваем GPIO13 (регистр 7) на вход и подтягиваем к плюсу (в случае, если будет отсутствовать внешнее сопротивление подтяжки).
5. Настраиваем GPIO2 (регистр 4) на вход и подтягиваем к плюсу (в случае, если будет отсутствовать внешнее сопротивление подтяжки для датчиков температуры DS18B20).
6. Подключаем датчик BME280 на GPIO14 (регистр 5) и GPIO12 (регистр 6).
7. Читаем данные температуры, влажности, давления, приведенного давления на уровне моря, высчитываем значение точки росы с датчика BME280.
8. Реализуем функцию альтиметра по барометрической формуле.
9. Определяем сколько подключено датчиков DS18B20 и считываем значения температур в массив, подчищаем память.
10. Читаем напряжение питания через adc.readvdd33().
11. Настраиваем радиотракт на режим клиента к первой точке доступа с именем SSID1, задаем пароль PASS1 для подключения.
12. Создаем таймер с периодом срабатывания 2000 мс.
13. В потоке таймера осуществляем проверку получения IP адреса нашим модулем от DHCP сервера первой точки доступа.
14. Если адрес не получен в течение более 2 секунд, пробуем подключиться ко второй точке доступа с именем SSID2, задаем пароль PASS2.
15. Если адрес не получен со второй точки,  останавливаем таймер и переводим модуль в ”спящий” режим командой node.dsleep() на 5 минут.
16. Если адрес получен, то останавливаем таймер и лезем сокетом на сервер 'utcnist2.colorado.edu' по порту 13. Из полученных данных выковыриваем дату и время с коррекцией последней на часовой пояс (политический перевод времени не учитываем).
17. По закрытию сокета подключаем скрипт работы с Интернет-сервисами и подчищаем память через collectgarbage().
18. В скрипте работы с Интернет-сервисами задаем переменные для хранения API ключей доступа к приложениям ThingSpeak, включая Twitter.
19. Выделяем из полученного времени только часы командой string.sub() и сравниваем с "13" или "21".
20. Если время совпадает, производим запись в EEPROM модуля текущего значения температуры с датчика BME280 командой file.write() в файл с именем ‘t13.log’ для 13 часов и 't21.log' для 21 часа.
21. Тут же производим чтение из файлов ‘t13.log’ и 't21.log' значений температуры, сохраненных ранее в переменные t13 и t21.
22. Читаем системный таймер с момента пробуждения и вызываем функцию SendData() работы с Интернет-сервисами.
23. В теле функции создаем сокет для соединения с сервисом thingspeak.com, передаем GET запросом параметры датчиков.
24. Не разрывая соединения, POST запросом на тот же сервер, но уже для Twitter-приложения, шлем комплексные параметры метеостанции, включая рассчитанные краевые вероятности заморозков из функции ves(), точки росы, давления, температуры и альтиметра.
25. По завершению соединения чистим память командой collectgarbage() и уводим модуль в “спящий” режим.

Реализация подобного подхода в терминах Lua представлена ниже.
t={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} -- список датчиков
-- 0- температура на улице
-- 1- температура картошки
-- 2- температура в комнате
-- 3- температура на кухне
local GMT=2 -- UTC+2
--dat -- UTC 16-12-11`
--tim -- UTC 11:05:29
-- sleep us = 300 sec
COUNTSLEEP = 300000000
-- читаем ADC до активации коннекта (вызывает сброс после)
wifi.sta.disconnect()
wifi.sta.autoconnect(0)
u=adc.readvdd33()/1000
--print("U="..u)
tpin=4 -- GPIO2
gpio.mode(tpin,gpio.INPUT,gpio.PULLUP)
bme280.init(5,6) --GPIO14/SDA GPIO12/SCL
to,p,h,q=bme280.read(86)
if to==nil then --fix
to=2500
p=1013000
h=30000
q=1013250
end
-- температура
temp=string.format("%d.%02d",to/100,to%100)
--print("Temperature: "..temp)
-- влажность
humi=h/10
humi=string.format("%d.%02d",humi/100,humi%100)
--print("Humidity: "..humi)
-- точка росы
d=bme280.dewpoint(h,to)
dew=string.format("%d.%02d",d/100,d%100)
--print("Dew point: "..dew)
-- пересчет
--dew2=temp-(100*(1-(humi/100))/5)
--print("Dew point2: "..dew2)
-- давление
pp=0.75*p/10
pp=string.format("%d.%02d",pp/100,pp%100)
--print("P: "..pp)
-- высота по барометрической формуле
xx=p/q--1013250
-- давление над уровнем моря 760 мм.рт.ст.=1013.25гПа
q=0.75*q/10
pm=string.format("%d.%02d",q/100,q%100)
--print("Pm: "..pm)
if xx<1 then xx=xx-1 end
if xx>1 then xx=1-xx end
yy=xx-(xx*xx/2)+(xx*xx*xx/3)-(xx*xx*xx*xx/4)
alt=-100*8.31*(temp+273.15)*yy/(0.029*9.81)
alt=string.format("%d.%02d",alt/100,alt%100)
--print("Altitude: "..alt)

local function reads18b20()

ds=require('ds18b20')
ds18b20.setup(tpin)
adr=ds18b20.addrs()
n=table.getn(adr) -- кол-во датчиков
for i=0, n-1, 1 do -- заполнение данными
t[i]=ds18b20.read(adr[i+1])-1
end
ds=nil
end
local function ves2()
conn=nil
conn=net.createConnection(net.TCP, 0)
conn:on("receive", function(conn, payload)
local dts=string.sub(payload,14,15)
local tms=string.sub(payload,17,18)
tms=tms+GMT
if tms==24 then
tms="00"
dts=dts+1
end
if tms==25 then
tms="01"
dts=dts+1
end
-- current date
dat=dts.."-"..string.sub(payload,11,12).."-"..string.sub(payload,8,9)
-- current time
tim=tms..string.sub(payload,19,24)
end)
conn:on("disconnection", function(conn, payload)
collectgarbage()
dofile("httpsender.lua")
end)
conn:connect(13,'utcnist2.colorado.edu')
end

reads18b20() -- fix предварительное чтение

r=tmr.now()
collectgarbage()

local function conap(nam,psw)

print("Setting up Wi-Fi...")
wifi.setmode(wifi.STATION)
wifi.sta.config(nam,psw)
wifi.sta.connect()
end
local cnt=0
local md=0
local trigger=0
conap("SSID1","PASS1")

tmr.alarm(1, 2000, 1, function()

if (trigger==0) then --TRIGGER
if wifi.sta.getip()==nil then
print("Get IP, Wait...")
cnt=cnt+1

if (cnt>2)and(md==0) then
md=1
cnt=0
conap("SSID2","PASS2") 
end
if (cnt>3)and(md==1) then
tmr.stop(1)
print("Sleep 300 sec...")
node.dsleep(COUNTSLEEP)
end
else
trigger=1
cnt=0
print("Config done, IP is "..wifi.sta.getip())
ves2()
collectgarbage()
end
end -- END TRIGGER
if(trigger==1)then
cnt=cnt+1
if(cnt>2)then --Timeout
tmr.stop(1)
print("Sleep Timeout...")
node.dsleep(COUNTSLEEP)
end
end
end)
Скрипт прогнозирования заморозков, комфортности, работы с файлами и отсылки данных в облако Thing и Twitter:
-- Прогноз заморозков по таблице Броунова
-- по мотивам погодного бота USB.HID
-- Определение точки росы по H/T
-- Определение высоты по P/T
local APIKEY3="APIKEY3" -- ключ APP TWITTER
local APIKEY1="APIKEY1" -- ключ на первые 8-датчиков
local APIKEY2="APIKEY2" -- ключ на вторые 8-датчиков
local dpin=7 --registr 7(GPIO13)
gpio.mode(dpin,gpio.INPUT,gpio.PULLUP)
g=gpio.read(dpin)
-- options
local function options(wr, fn, it)
if(wr==0)then
file.open(fn..".log", "r")
ot=tonumber(file.readline()) --преобразуем строку в число
file.close()
end
if(wr==1)then
file.open(fn..".log", "w")
file.write(''..it..'')
file.close()
end
return ot
end
-- likelihood of frost
local function ves(dat,tim)
-- разница между температурой в 13 и 21 час
local y=t21
local x=y-t13
-- краевые вероятности
local y10=11+(3*x/8)
local y20=8.5+(4.5*x/11)
local y40=6.5+(4.5*x/11)
local y60=4.5+(4.5*x/11)
local y80=2.5+(4.5*x/11)
-- принадлежность точки области графиков
if(y>y10)then rs="%20Frosts%200%25" end
if(y10>=y)and(y>y20)then rs="%20Frosts%2020%25" end
if(y20>=y)and(y>y40)then rs="%20Frosts%2040%25" end
if(y40>=y)and(y>y60)then rs="%20Frosts%2060%25" end
if(y60>=y)and(y>y80)then rs="%20Frosts%2080%25" end
if(y80>=y)then rs="%20Frosts%20100%25" end
return "%5B"..dat.."%20"..tim.."%5D"..rs
end
--comfort dewpoint
--local function comfort(dew)
--if(dew>26)then cmf="dangers%20asthmatics" end
--if(dew>=24)and(dew<=26)then cmf="uncomfortable%20condition" end
--if(dew>=21)and(dew<24)then cmf="damp%20uncomfortable" end
--if(dew>=18)and(dew<21)then cmf="uncomfortable" end
--if(dew>=16)and(dew<18)then cmf="comfortable,%20but%20humid" end
--if(dew>=13)and(dew<16)then cmf="comfortable" end
--if(dew>=10)and(dew<12)then cmf="very%20comfortable" end
--if(dew<10)then cmf="dry" end
--return cmf
--end
local function sendData()
param1="%20(To%20"..temp.."%C2%B0C,%20Tr%20"..dew.."%C2%B0C,%20P%20"..pp.."mmHg,%20H%20"..humi.."%25,%20Alt%20"..alt.."m),"
param2="%20Ti%20"..t[0].."%C2%B10.5%C2%B0C,%20Uion%20"..u.."V,%20TimeUP%20"..r.."us"
param=param1..param2
srv=nil
srv=net.createConnection(net.TCP, 0)
srv:connect(80,"184.106.153.149")
srv:on("receive", function(sck, c) end)
srv:on("connection", function(sck, c)
sck:send("GET /update?key="..APIKEY1.."&field1="..temp.."&field2="..u.."&field3="..g.."&field4="..r.."&field5="..humi.."&field6="..t[0].."&field7="..pp.."&field8="..dew.." HTTP/1.1\r\n")
sck:send("Host: api.thingspeak.com\r\n")
sck:send("Accept: */*\r\n")
sck:send("User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n")
sck:send("\r\n")
sck:send("POST /apps/thingtweet/1/statuses/update?api_key="..APIKEY3.."&status="..ves(dat,tim)..param.." HTTP/1.1\r\n")
sck:send("Host: api.thingspeak.com\r\n")
sck:send("Accept: */*\r\n")
sck:send("User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n")
sck:send("\r\n")
end)
srv:on("disconnection", function(sck, c) end)
srv:on("sent",function(sck, c)
collectgarbage()
print("Sleep 300 sec down...")
node.dsleep(COUNTSLEEP)
end)
end
--SAVE EEPROM
if(string.sub(tim,1,2)=="13")then options(1, "t13", temp) end
if(string.sub(tim,1,2)=="21")then options(1, "t21", temp) end
--READ EEPROM
t21=options(0,"t21",temp)
t13=options(0,"t13",temp)
--SEND
sendData()
Экономим память

В начале нашего цикла мы упоминали о способах экономии оперативной памяти в NodeMCU. В текущей реализации метеостанции ввиду большого количества датчиков желательно использовать упомянутую команду 'node.compile()’ из терминала загрузчика LuaLoader для предварительной компиляции двух скриптов 'ds18b20.lua' и ‘httpsender.lua’ (см. ресурсы). После чего, перед запуском скрипта инициализации 'init.lua', удалите 'ds18b20.lua' и ‘httpsender.lua’ (соответствующие им файлы *.lc останутся и будут доступны интерпретатору). После запуска 'init.lua' можем перейти на http://thingspeak.com/channels/113125 и в Twitter и проверить работоспособность метеостанции:






Ресурсы и ссылки
  1. Прозрачный мост UART/Wi-Fi --- Wi-Fi/UART на базе ESP8266 на Lua 
  2. Wi-Fi лампа. Контроль DIO модуля ESP-01 (ESP8266) по Wi-Fi  
  3. Монтаж мезонином прозрачного моста Wi-Fi-UART на ESP8266
  4. Автономный датчик температуры по Wi-Fi на базе ESP8266
  5. Аномальная разрядная кривая ионисторов проекта "вечный" Wi-Fi логгер. Луна однако
  6. Работа "вечного" Wi-Fi логгера на солнечную панель из... аморфного кремния 
  7. #ESP.Meteo: Wi-Fi логгер с автономным питанием в Twitter-e  
  8. Вывод отладочной информации с ESP-12 на дисплей SSD1306
  9. Медианная фильтрация для датчика температуры и влажности DHT
  10. Выносной DHT вечного Wi-Fi логгера с питанием от солнечной панели и ионисторов
  11. #ESP.Meteo под дождем
  12. Документация по Lua http://www.lua.ru/doc
  13. Онлайн-билдер NodeMCU http://nodemcu-build.com
  14. Терминал LuaLoader для загрузки скриптов Lua https://github.com/GeoNomad/LuaLoader
  15. СНиП II-1-82. Строительная климатология и геофизика, М.: Стройиздат, 1982.
  16. Сербинович П.П. Архитектура гражданских и промышленных зданий. Гражданские здания массового строительства, М.: Высш. школа, 1975.
  17. Данные REALTIME автономной метеостанции (WLAN-логгера) с питанием от солнечной панели и ионисторов в Twitter https://twitter.com/ramedias (температура и влажность на улице, температура на балконе, напряжение на ионисторе, время работы между спящими режимами + прогнозирование заморозков по методике профессора Броунова).
  18. Тренд уличной температуры 
  19. Тренд уличной влажности 
  20. Тренд температуры на балконе 
  21. Тренд состояния дискретного датчика заслонки ящика для картошки 
  22. Тренд чередования режимов сна-бодрствование 
  23. Тренд напряжения питания 
  24. Видеодемонстрация работы #ESP.Meteo 
  25. #ESP.Meteo. Обновление ПО на Lua по воздуху

2 комментария:

  1. Дополнил метеостанцию прогнозом ВНГО (высоты нижней границы облачности - Cloud Forecast) по методике Селезневой.

    ОтветитьУдалить
  2. Обратите внимание на таймаут в коде выше: при случайном разрыве соединения сокет будет висеть до бесконечности и модуль будет продолжать работать, так вот для фикса сего сразу после вызова функции запроса времени таймер мы не останавливаем, а отсчитываем еще две секунды по истечении которых мы принудительно переводим модуль в спящий режим. Не успел получить время и отослать - твои проблемы, надо экономить энергию. Двух секунд более чем достаточно для работы с Интернет-сервисами, а в нашем случае на все про все не более 780-800 мс.

    ОтветитьУдалить

В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.