Андрей Смирнов
Время чтения: ~25 мин.
Просмотров: 14

Делаем бюджетный чудо корабль с управлением по WiFi на базе ESP8266.

25 июня 2019, 23:00

Как разрабатываются устройства IoT? Это сложно? Китайская компания Espressif Systems в свое время сделала переворот в индустрии IoT, представив свой новый чип ESP8266 по необычайно низкой цене, ставший культовым для производства DIY устройств умного дома. Под новый чип от  Espressif Systems программисты начали активно писать библиотеки и адаптировать существующие библиотеки платформы Arduino. Это сделало разработку IoT устройств необычайно простой и увлекательной. Сегодня существует множество коммерческих устройств на базе чипа ESP8266. Я решил поделиться с вами своим опытом создания устройства IoT на базе чипа ESP8266. 

Сколько вольт «в розетке»?

Большинство ответит: около 220 вольт и будут правы, но не совсем. Напряжение в сети питания представляет собой синусоиду с амплитудой около 311 вольт (tnx to AlexAW), на четверти цикла которой напряжение равно 110 вольт, а иногда и вовсе равно нулю!

1600x_image.png?1561559263

Тоесть, если включать нагрузку каждый раз, когда синусоида приближается к нуля, можно напрямую без адаптеров из розетки заряжать мобильный телефон! 

1600x_image.png?1561225465

Для определения точки, когда в сети напряжение равно нулю я воспользовался вот таким устройством от китайских товарищей из RobotDyn стоимостью 230 руб. Он уже содержит в себе сразу детектор нуля (zero-cross detector) и симмистор, который открывается при подаче импульса управления, оставаясь открытым до тех пор пока питающее напряжение не упадет практически до нуля. Для получения нужного  напряжения на выходе мы должны синхронизировать сигнал управления с переходом синусоиды питающего напряжения через ноль. Управление силовым симмистором заведено  через маломощный оптосиммистор, поэтому цепи управления гальванически развязаны с сетевым напряжением. Каждый раз, когда сетевое напряжение приближается к нулю, модуль  подает сигнал на один из своих выходов. Смещая фазу включения симмистора путем подачи управляющего сигнал на другой пин модуля можно получить на выходе любое напряжение в пределах от 220 вольт до нуля. 

Управлять этими сигналами мы будем с помощью модуля nodemcu, на борту у которого установлена ESP8266. Подключаем пины Z-C и pwm к цифровым пинам ESP8266, подаем питание на модуль и… Ничего не происходит! Верно, нам необходимо еще написать свою прошивку для модуля. Устанавливаем Atom и PlatformIO и приступаем к написанию микропрограммы. Китайские товарищи из RobotDyn уже написали библиотеку для управления таймерами, что упрощает  написание микропрограммы для модуля. Хотя так было не всегда, библиотека появилась около полугода назад, в первоначальной версии прошивки я использовал собственный код для диммирования. 

1600x_image.png?1561227573

Что должно уметь наше устройство?

Во-первых, конечно, оно должно управляться из внешних систем по радиоканалу (Wi-Fi в нашем случае): должно принимать команды и отправлять ответ о результате их выполнения. Во-вторых, должна быть возможность найти устройство в сети. И конечно же, возможность обновления «по воздуху» (OTA Update).  Приступим к реализации. Полный листинг кода прошивки я думаю будет интересен небольшому кругу читателей, поэтому всю программную реализацию я оставлю «за кадром», сосредоточимся на принципиальном проектировании устройства. 

Наше устройство должно быть безопасным. Т.к. во время циклов включения-выключения наш транзистор нагревается, установим на плату вот такой простой термодатчик DALLS DS18B20 за 35 рублей. Датчик обменивается с микроконтроллером данными по однопроводной линии связи интерфейса 1-Wire, диапазон измерения температуры составляет от -55 до +125 градусов цельсия, этого должно нам вполне хватить. После превышения температуры 40 градусов, устройство автоматически отключит само себя и перестанет принимать команды до того, пока температура не снизится.  Callback функция отключения выглядит следующим образом:

void emergencyCallback() {    sensors.requestTemperatures();    float temperature = sensors.getTempC(insideThermometer);      if (temperature > 40) {      dimmer.setState(OFF);      digitalWrite(LED_PIN, LOW);      Serial.printf("Temperature is %.2f degrees celsius. Swith OFF on emergency reason.nr", temperature);    } else Serial.printf("Temperature is %.2f degrees celsiusnr", temperature);    }  

Подключаем все по следующей схеме:

Для корректной работы датчика между пинами DATA и VDD необходимо припаять резистор на 4,7 кОм. Конфигурация пинов следующая:

#define LED_PIN D6  #define AC_LOAD D8  #define ZC_PIN D1  #define ONE_WIRE_BUS D5

Собираем все на макетной плате:

Чтобы устройством можно было управлять, поднимем на нашей ESP8266 TCP сервер на порту 2000. Для отправки на устройство команд я выбрал текстовый формат сериализации и десериализации данных json т.к. он легко читается как людьми, так и машиной, не придется писать свой парсер, можно отправлять и принимать произвольное количество параметров, да и просто с ним удобно работать в целом (особенно в python). Какие команды нам могут понадобится?

{"id":1, "method":"set_power", "power":"50", "state":"ON"}  {"id":1, "method":"set_power", "power":"50", "state":"OFF"}  {"id":1, "method":"set_state", "state":"OFF"}  {"id":1, "method":"set_state", "state":"ON"}  {"id":1, "method":"set_config", "SSID":"Wi-Fi SSID", "PASSWD": "PASSWORD"}  {"id":1, "method":"set_mode", "mode":"TOGGLE_MODE"}  {"id":1, "method":"get_temperature"}  {"id":1, "method":"get_state"}  {"id":1, "method":"update", "IP":"192.168.1.43", "url":"/update/firmware.bin"}  

Параметр method определяет команду для выполнения, set_power устанавливает яркость освещения (диммирование), state — определяет включена или выключена при этом нагрузка. Это может быть удобно, когда в системах управления умным домом вызывается метод «включить» без установки уровня диммирования, в этом случае при включении будет установлен заданный ранее (например, в сцене по времени) уровень освещенности. set_state включает или выключает нагрузку, set_config — посылает на устройство конфигурацию Wi-Fi сети. При первом включении (либо в случае невозможности подключиться к существующей сети) наше устройство переходит в режим точки доступа (с адресом 192.168.4.1), подключившись к которой можно отправить конфигурацию нашей Wi-Fi сети. get_temperature возвращает текущую температуру с сенсора, get_state — текущий статус (выключено или включено), метод update инициирует обновление прошивки, он принимает в качестве параметров IP адрес сервера, на котором находится обновление и сам путь к этом обновлению (url). Само обновление можно, например, разместить в локальной сети на малинке. Отправить команды можно прямо из терминала с помощью утилиты netcat. На запрос

echo '{"id":1, "method":"get_state"}' | nc -w1 192.168.1.43 2000

получим ответ:

{"id":1,"power":30,"state":"ON"}

Для чего нужен id? Дело в том, что ESP8266 отправляет ответ всем подключенным клиентам и чтобы различать ответы, которые предназначены именно нам как раз и нужен id запроса. 

echo '{"id":1, "method":"get_temperature"}' | nc -w1 192.168.1.43 2000

вернет нам текущую температуру с датчика DS18B20

{"id":1,"temperature":21.9}

Уже сейчас наше устройство можно интегрировать с системами управления умным домом путем выполнения shell команд, например можно легко добавить в homebridge, который прокинет устройство в HomeKit. 

Demo

Статические IP. Не люблю я статические IP, поэтому для своего устройства я предусмотрел возможность сетевого поиска. 

void discoverResponder() {        if (Udp.parsePacket()) {        char packetBuffer[255] = "";        if (Udp.read(packetBuffer, 255) == 0) return;        Serial.printf("Received broadcast message: %s from %sn", packetBuffer, Udp.remoteIP().toString().c_str());          if (String(packetBuffer) == "discover") {          Udp.beginPacket(Udp.remoteIP(),Udp.remotePort());          StaticJsonDocument jsonResult;            jsonResult["deviceID"] = String(ESP.getChipId(), HEX);          WiFi.localIP() ? jsonResult["IP"] = WiFi.localIP().toString() : jsonResult["IP"] = WiFi.softAPIP().toString();          jsonResult["model"] = MODEL;            String jsonReply;          serializeJson(jsonResult, jsonReply);            Udp.print(jsonReply);          Udp.endPacket();        }      }  }  

Для поиска в сети ESP8266 DIY Smart Home устройств достаточно отправить на порт 1000 широковещательный UDP пакет с содержанием «discover». Скрипт (поиска) на Python выглядит так:

import json  import socket    print('Starting discover ESP8266 DIY Smart Home devices...')  helobytes = 'discover'.encode()    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)  s.settimeout(5)  s.sendto(helobytes, ('<broa00 data="" addr="s.recvfrom(1024)" reply="json.loads(data.decode())" deviceid="reply[&quot;deviceID&quot;]" ip="reply[&quot;IP&quot;]" hardware="reply[&quot;hardware&quot;]" print="" device="">

 В результате придет ответ:

{"deviceID":"d7531с","IP":"192.168.1.43","hardware":"ZCACD1"}

Здесь deviceID — уникальный идентификатор нашего устройства, нужен для того, чтобы различать несколько устройств в одной сети, IP — IP адрес, необходимый для отправки на устройство команд. 

Прошивка ESP8266

Заливать пошивку мы будем с помощью инструментов esptool и nodemcu-pyflasher. Устанавливаем. 

git clone https://github.com/espressif/esptool.git  cd esptool  sudo python setup.py install  

После установки esptool запускаем nodemcu-pyflasher. Здесь нужно указать порт загрузки — он появляется после после подключения USB to TTL конвертера (либо после подключения USB кабеля если конвертер уже распаян на плате), путь к нашей прошивке, скорость можно оставить 115200. В случае ошибок загрузки, скорость нужно уменьшить, например до 9600. Указываем нужно ли нам стирать все данные на флеш памяти ESP, нажимаем кнопку Flash NodeMCU, ждем несколько секунд — все готово! Иногда перед подключением ESP к компьютеру нужно зажать на плате кнопку «flash», а уже потом подключать питание. Если кнопки flash нет на плате, просто замыкаем контакты GPIO0 и GND, затем подаем питание, это переведет наш модуль в режим прошивки, позволяя загрузить нашу микропрограмму на устройство. 

Интеграция в Domoticz

В конечном итоге я делал устройство для интеграции в системы управления умным домом. Можно конечно подключить его через shell скрипты, но ничто не сравнится с нативной поддержкой, «родные» устройства в Domoticz имеют  наивысший приоритет и работают очень шустро, к тому же будет обратная связь от устройства со статусом выполненной команды (включилось/выключилось), более того, появляется возможность реализовать коммуникацию напрямую через сокеты, что добавит скорости и стабильности нашему устройству. Настройка довольно проста и похожа на настройку других моих плагинов для Domoticz:

Для настройки необходимо ввести только deviceID, встроенная система поиска «discover» сама найдет устройство в сети. Для получения deviceID при первой настройке нужно просто оставить поле равным 0, это запустит режим сетевого поиска и в логе Domoticz будет отображен deviceID, который нам нужен. 

После запуска плагин создает выключатель типа диммер, и набор сцен. Bright — яркая сцена, TV — приглушенный до 30%  свет, Daily — включенный на половину диммер, Midnight — минимальное освещение. Можно так же реализовать аппаратные сцены, такие как «восход» или «закат» — все в наших руках! Дополнительно создается температурный сенсор с датчика DS18B20, который можно найти во вкладке «Температура». 

Для установки плагина клонируем репозитарий:

cd domoticz/plugins  git clone https://github.com/Whilser/ESP-DIY-Samrt-Home.git ESPSmartHome  sudo service domoticz restart

Там же, в репозитарии находится прошивка для модуля: файл firmware.bin.

Больше, чем просто диммер

По сути, наше устройство может измерять и посылать окружающую температуру. Да, если его расположить в корпусе, оно будет измерять внутреннюю температуру, но если вывести его за пределы корпуса — получится дополнительный термодатчик. Если заменить Zero-Cross Detector на реле (например, твердотельное), то получим умную розетку и все это легко интегрируется в систему умного дома, более того, имеется нативная поддержка системы управления умным домом Domoticz. Если закачать прошивку в существующее устройство на базе  ESP8266 (например, sonoff), или светодиодную лампочку (с некоторыми переделками, конечно), получим IoT устройство с нужным нам функционалом, это может говорить о том, что наш проект можно превратить в базовую платформу для разработки недорогих IoT устройств с нужным нам функционалом. Именно для этого в функции discover предусмотрена передача модели устройства. 

Что дальше?

Прототип получился немного громоздким, но на то он и прототип. Устройство можно уменьшить в размерах если:

  • Разработать и напечатать собственную плату
  • Нарисовать и напечатать корпус

Следующим устройством семейства DIY Smart Home будет счетчик воды для информирования о ресурсе фильтра питьевой воды и необходимости его замены. Спасибо за вдохновение Виталию. Так же я планирую доработать текущую прошивку, добавив некоторые аппаратные сцены (такие как восход, закат и может быть что-то еще).

Разработка собственных IoT устройств может быть довольно увлекательным занятием, время пролетает незаметно! Можно легко получить устройство с нужным мне функционалом. В дальнейшем я планирую развивать проект, разрабатывая все новые устройства с нужным мне функционалом, дорабатывая поддержку устройств в системе управления умным домом Domoticz (да, я знаю про существование Home Assistant, но так уж исторически сложилось, что начал строить свой умный дом на платформе Domoticz и если все работает и работает хорошо — не вижу особого смысла менять платформу, а все нужные мне устройства, поддержки который нет в Domoticz я могу легко и увлекательно добавить сам… ). 

Ссылка на проект GitHub: DIY Smart Home based on Espressif Systems (ESP32, ESP8266). Там правда пока мало чего документировано, но со временем я добавлю туда материалы. 

Если Вы ходите собрать подобное устройство, Вам понадобятся комплектующие, купить которые Вы сможете по ссылкам:

  • Цена: $3.05

Подробное руководство о том как взять ESP8266, добавить немножко клея и пенопласта и подарить детям (и взрослым) массу удовольствий. Руководство состоит из следующих частей:Описание платыПредысторияИспользуемые материалыИзготовление корабляПрограммированиеПлаваниеОписание платы. Мозгом корабля является купленная на Алиэкспресс плата. Данная отладочная плата является удобным средством для начала работы с WiFi модулем ESP8266-12. На плате распаян сам модуль, а на штыревые разъёмы выведены все выводы модуля. К 6-ти выводам через токоограничительные резисторы припаяны красные светодиоды. Ещё к трём выводам припаян RGB светодиод. Также присутствует стабилизатор 3,3 В, распаяны резисторы обвязки модуля, на входе ADC висит фоторезистор, присутствует джампер для перевода модуля в режим программирования. Отдельно выведены выходы USART, причём маркировка Rx и Tx перепутаны местами. Ко входу питания модуля припаян батарейный отсек на 3 батарейки. А в модуль уже загружена тестовая прошивка под управлением которой, насколько я помню, создаётся новая точка доступа. Подключившись к этой точке доступа можно управлять свечением светодиодов на плате. Если как для первого раза — то это прям волшебство какое то. Предыстория постройки кораблика. В процессе вялотекущего самообразования в сторону построения умного дома, год назад был закуплена эта плата (магазин в котором была сделана покупка сейчас закрыт). Вместе с ней взял ещё два голых модуля ESP8266-12 и с помощью сайта запустил на них два термометра/измерителя влажности, которые до сих пор успешно работают. Далее попытался состыковать их с MajorDoMo — открытой и бесплатной системой управления Умным Домом. Но как то не пошло это дело,- забросил до поры. В середине лета я наткнулся на статью. Оказывается esp8266 можно программировать как любую ардуину!!! И ардуиновских библиотек под esp8266 портировано уже на все случаю жизни. Для меня настал качественно новый этап освоения esp8266… Вдоволь поигрался с библиотечными примерами и захотелось мне сделать нечто с практическим применением. Решил собрать детям для дачного водоёма самоходный кораблик, да не простой, а такой чтоб управлять им можно было с любого смартфона!В началоИспользуемые материалы На строительный материал корпуса были выбраны пылящиеся в кладовке куски пенопласта. В качестве двигателей использованы коллекторные моторы от ДВД проигрывателя. Для управления судна было решено использовать двухмоторный привод — уменьшая обороты левого/правого двигателя заставляем совершать поворот на лево или на право. Гребные винты — из куска жести. На гребные валы замечательно подошли вязальные спицы (экспроприированные у супруги). Для надёжного и гибкого соединения гребного вала с мотором хорошо подходят термоусадочные трубки разного диаметра. В качестве подшипника скольжения гребного вала взят корпус простой шариковой ручки. Также пригодились клей Dragon и клеевой термопистолет. Для управления двигателями в загашнике нашлись два полевых транзистора выпаянных со старой материнской платы. Источником питания послужили купленные в оффлайне аккумуляторы 18650. Ещё понадобился маленький тумблер для подачи питания, несколько резисторов и макетная платка для соединения всего электричества между собой.В началоИзготовление корабля Для резки пенопласта на скорую руку был собран ТермоЭлектроРезак состоящий из палки, двух длинных шурупов и куска тонкой проволоки. Проволоку лучше взять нихромовую, но у меня таковой не нашлось (а советский проволочный резистор ломать на это дело не хотелось) — поставил тоненькую стальную. Запитал этот импровизированный станок от «народного блока питания» через DC-DC преобразователь. И тот и другой были куплены благодаря здешним обзорам. Всего на этой фотографии пытливый взгляд может найти аж 10 товаров ранее обозреваемых на Муське. Регулируя напряжение на выходе DC-DC преобразователя, опытным путём необходимо установить такой нагрев проволоки ТермоЭлектроРезака, при котором пенопласт разрезается легко и непринуждённо. В итоге получаем более — менее ровные куски пенопласта удобные для последующей сборки. На корпус кораблика пошли два самых больших куска, склееные между собой клеем Дракон. Гребные винты изготавливаются в несколько операций: — нарезать из жести квадратную заготовку (у меня 20*20 мм) — соединив рисками диагональные углы найти центр — просверлить по центру отверстие (диаметр 3,5 мм) — затянуть подходящим винтом с гайкой (М 3*20) — зажав винт в патрон дрели, на малых оборотах подходящим острым предметом начертить(нацарапать) окружность — вырезать ровный круг — надрезать по имеющимся диагональным рискам круг на 2/3 радиуса и изогнуть под углом (30-45 градусов) Затем берём спицу. Отрезаем 25-30 мм кусок термоусадочной трубки диаметром чуть больше чем у спицы. Вращаем спицу с термоусадкой над маленьким пламенем газовой конфорки (или электрической) пока трубка не прогреется и плотно охватит спицу. Далее отрезаем кусок трубки ещё большего диаметра,… и т.д. пока очередную трубку можно будет одеть на шестерню двигателя. Т.К. шестерня посажена на вал двигателя достаточно плотно, то она будет хорошо передавать крутящий момент гребному валу. Берём последний кусок термоусадки и одеваем его одновременно на гребной вал и на двигатель. После прогрева термоусадки получаем хорошее соединение.

Пора устанавливать двигатели в корпус. Дрелью высверливаем в корпусе два отверстия под гребные валы. Со стороны днища вставляем подшипники скольжения. Выставляем двигатели и прокручивая вал, по наименьшему сопротивлению вращения, находим для каждого двигателя оптимальное положение. Обильно закрепляем полученный результат термоклеем.
Одеваем гребные винты и закрепляем термоклеем. Для лучшего сцепления с клеем кончики спиц слегка помяты кусачками, а поверхности винтов около центра исцарапаны до шершавого состояния. Соединяем и спаиваем всё согласно схеме. Питание с аккумуляторов подаётся через тумблер и дальше идёт на двигатели и на линейный стабилизатор 3,3 В. Второй вывод каждого двигателя подключен через полевой транзистор к минусу питания. Подавая с выхода ESP8266 за затвор полевого транзистора ШИМ сигнал различной скважности импульсов мы будем регулировать скорость вращения двигателя. Напряжение питания также подаётся через резистивный делитель на вход ADC модуля ESP8266 для контроля состояния батареи. Силовые транзисторы с резисторами обвязки, выключатель питания, стабилизатор, резистивный делитель для измерения напряжения батареи — всё размещено на макетной плате. К ней же припаяны плата с модулем ESP8266, выводы аккумулятора и двигателей. К модулю подключен переходник USB-TTL. Итак, всё готово для того чтобы вдохнуть в практически готовый кораблик искру жизни…В началоПрограммирование О том как установить Arduino IDE и обеспечить в ней поддержку ESP8266 достаточно хорошо расписано в вышеупомянутой статье. Для управления корабликом мы будем создавать на ESP8266 точку доступа и поднимать вэб сервер. Подключившись смартфоном к точке доступа и набрав в браузере адрес сервера (192.168.4.1) увидим страницу с элементами управления и телеметрией с борта нашего судна. Дабы снизить нагрузку на ESP8266, уменьшить время отклика управляющих воздействий и повысить интерактивность я решил использовать технику AJAX запросов.Выдержка из Википедии: Помучав некоторое время Гугл в поисках подходящей реализации моих хотелок, я набрёл на форум в котором позаимствовал подходящий кодПервоначальный код Путём последовательных приближений код был доведён до нужного мне рабочего варианта.окончательный код В коде довольно много пояснений, надеюсь всё будет понятно. Двигатели кораблика управляются путём изменения положения ползунков трёх слайдеров на странице. — Первый слайдер отвечает за скорость вращения моторов (и скорость движения кораблика соответственно). Если изменять положение ползунка этого слайдера от 20 до 100%, то будет меняться значение связанной со слайдером переменной ESPval[0]. Значение переменной записывается в порты OUT1 и OUT2 ESP8266 (выводы которых идут на управляющие затворы полевых транзисторов) и обороты двигателей будут нарастать от 0 до максимума. В диапазоне положений этого ползунка от 0 до 20% в порты записываются 0 и двигатели стоят. — Второй слайдер отвечает за повороты (переменная ESPval[1]). Если его ползунок находится в правом или левом положении, то значение скорости соответствующего двигателя будет снижаться на коэффициент 0,8 (константа Povorot). Двигатель будет притормаживаться, а кораблик поворачивать в нужную сторону. — Третий слайдер (переменные ESPval[2] и Trimer) нужен для нивелирования разности характеристик двигателей. В зависимости от положения слайдера можно притормаживать или ускорять один из двигателей. К сожалению функционал измерения напряжения батареи довести до конца не удалось. В процессе наладки был сожжён вход ADC модуля (надо думать замкнул его на + батареи)… Измерение мощности сигнала WiFi работает, но требуется более точная калибровка. Для отладки использовалось подключение к домашней WiFi сети и вывод информации в последовательный порт. В рабочей же версии кода модулем поднимается отдельная точка доступа и вывода не нужен — соответствующие строки кода закомментированны. Скетч компилировался в IDE версии 1.6.12. Свободной памяти осталось более чем достаточно для воплощения в коде разных последующих хотелок. Если у кого будут конструктивные дополнения/исправления по коду — прошу высказываться в комментариях.В началоПлавание Сначала были пробные запуски в акватории ванной, по результатам которых были сделаны следующие доработки: — 4 батарейки АА в источнике питания были безоговорочно заменены на 2 аккумулятора 18650 — к регулировкам скорости и поворота было добавлено триммирование одного из двигателей — был увеличен шаг гребных винтов Затем в ближайший выезд на дачу судно было было торжественно отправлено в плавание на большой воде. Полевые испытания показали что в следующей версии необходимо: — усилить мощность сигнала WiFi модуля путём добавления внешней антенны — увеличить диаметр гребных винтов (или заказать винты на Алиэкспресс ) — увеличить притормаживание двигателей при поворотах с 20% до 40-50% — доработать корпус для улучшения обтекания — заменить двигатели на бесколлекторные — сделать руль с приводом от сервомашинки — прикрутить FPV — добавить светодиодной иллюминации для ночных заплывов — установить на палубу фейерверк и запускать его на середине пруда — всё что душа пожелает… Но эти доработки возможно воплотятся уже в новом сезоне.В начало Вот так, приложив немного времени и средств, любой рукодел средней продвинутости сможет собрать свою радиоуправляемую игрушку. Без существенной переделки программы таким же нехитрым образом можно слепить управляемую машинку (или несколько машинок) для весёлых заездов по квартире долгими зимними вечерами. Буду рад если этот опус вдохновит кого либо для занятий творчеством. Умный домDIY или Сделай самВсем привет! В этой статье хочется рассказать, как заставить датчик влажности почвы проработать год на двух батарейках (ААА) и при этом сделать все более менее правильно. Первая статья — про выбор среды разработки (Arduino IDE) и платформу Blynk.44_gjojoheu6avdrsg4hprovyrm.jpegКартинка домашнего дуба для привлечения внимания

Садовод любитель

Для начала небольшое признание — я не программист и я домашний садовод. И то и другое это мое хобби. У меня на подоконниках сделаны полки, с специальной сине-красной светодиодной подсветкой, под которой растения должны расти с бОльшим энтузиазмом. Не вдаваясь в детали фотосинтеза и прочую ботанику, можно сказать, что светодиодная подсветка создала одну проблему, решая которую и родилось устройство, которому посвящена эта статья. Спойлер Светодиодные линейки (мощность примерно 6 Вт), достаточно сильно нагреваются сами и нагревают полку и горшок с растением, который на ней стоит. Самому растению, подогреваемая почва не приносит какого либо дискомфорта, но возникает проблема быстрого пересыхания почвы. При этом земля в горшках, которые стоят просто на подоконнике высыхает медленнее. А на верхних полках, там где во время полива не видно состояние почвы, регулярно случаются переливы или засухи. Конечно же все уже придумано, и на Ebay можно купить вагон разных измерителей влажности почвы. Например, был куплен один экземпляр измерителя влажности с бипером (цена около 300 рублей). q_tmj-50xur8_mmezzxiv1y9rtm.jpeg Устройство работает, но есть несколько но:

  1. Не понятно на какой уровень влажности настроен бипер.
  2. Если устройств будет больше чем одно, то придется ходить и прислушиваться.
  3. Я ведь тоже так могу.

И тут Остапа понесло, ведь есть опыт (раз и два). Так родилось устройство способное измерять влажность почвы, освещенность, температуру и влажность воздуха, передавать результаты измерений в мобильное приложение и работать при этом от батареек достаточно продолжительное время. Про железо тут. А про программные особенности хочется рассказать подробнее в этой статье.

Анализируем энергопотребление

Согласно даташита, ESP8266 потребляет до 170 мА в режиме работы WiFi, 15 мА с выключенным модемом (Modem Sleep) и совсем ничего в режиме Deep Sleep – примерно 10 мкА. Из потребляющего в нашем устройстве можно выделить WiFi модем, датчик AM2302 (на который подается 3.3 В через повышалку TPS60240DGKR) и мультиплексор (CD74HC4051M96) для коммутации входов АЦП. Самый большой вклад в энергопотребление вносит WiFi и поэтому первым делом надо заставить ESP8266 стартовать с выключенным радиомодулем. После загрузки в режиме Modem Sleep можно сделать все измерения и только потом включать модем и передавать данные на сервер Blynk (для оптимизации потребления MQTT пока отключил), после чего уже заснуть до следующего раза.

Deep sleeep

При условии, что аппаратно все ноги соединены правильно (RST пин соединен с GPIO16), перевести ESP в режим Deep Sleep можно одной командой:

ESP.deepSleep(sleep_time, WAKE_RF_DISABLED); 

sleep_time – время сна в микросекундах, которое можно динамически менять и если, скажем, попытка передать данные не удалась (не работает роутер или не отвечают сервер blynk) – то можно установить таймер на 5-10 минут и после попробовать передать данные снова. А если все хорошо, то после успешного сеанса связи можно уснуть на час или сутки.WAKE_RF_DISABLED — указывает на то, что проснется модуль с выключенным WiFi модулем.

Работа с WiFi

В этот раз также хотелось иметь возможность настраивать устройство без помощи компьютера через Captive портал. Но если, как в прошлый раз, взять библиотеку WiFiManager, то с выключенным модемом работать она будет как минимум странно. Поэтому всю логику работы данной библиотеки пришлось привязать к нажатию кнопки. А раз кнопка у нас всего одна и та используется для загрузки ПО через UART — то пришлось сделать так:

  1. Включаем питание (вставляем батарейки).
  2. Ждем мигание светодиода (в тестовом варианте слушаем бипер).
  3. Нажимаем кнопку и попадаем в WiFiManager.

Теперь мы можем открыть Captive портал, сохранить настройки WiFi и Blynk token. В следующую загрузку библиотека уже использоваться не будет, а подключаться к WiFi будем средствами самой ESP.

//будим модем WiFi.forceSleepWake();  //устанавливаем режим работы WiFi.mode(WIFI_STA);  //чуть чуть ждем delay(100); //проверяем, что сохранены параметры сети и делаем begin if (WiFi.SSID()) WiFi.begin();  

В некоторых мануалах по оптимизации энергопотребления ESP8266 можно встретить команду WiFi.disconnect(); которая должна отключать модем от текущей WiFi сети. Однако на практике, эта команда удаляет сохраненный в памяти модема SSID() и пароль, поэтому использоваться ее мы не будем.

Считываем датчик AM2302

Для работы с датчиком температурывлажности также была использована библиотека DHT Sensor Library от Adafruit. В целях экономии, питание на датчик подается не постоянно, а только по сигналу, специально выделенного GPIO. Однако, опытным путем установлено, что датчик достаточно продолжительное время выходит на рабочий режим и адекватные значения влажности (отличные от 99%) начинает выдавать примерно через 5 секунд после подачи на него питания. С одной стороны такая большая задержка на «прогрев» датчика это лишние мА, но возможность управлять питанием датчика AM2302 это скорее плюс, т.к. мы можем пользоваться датчиком не каждый раз или переставать измерять температурувлажность при снижении заряда батареек.

Измеряем показания на АЦП

АЦП у нас используется для измерения трех параметров: заряд батареек, освещенность и влажность почвы. Для коммутации разных сигналов на вход единственного АЦП — используется мультиплексор (модель). У ESP8266 АЦП 10-битный, а диапазон измеряемых напряжений 0..1 В. Поэтому в схеме предусмотрен резистивные делители, понижающий все измеряемые сигналы до уровня 1 В. При измерении заряда батареи — все замеры на графике выглядят правильно. Однако оказалось, что по мере снижения заряда батареек начали снижать и показания датчика яркости.guqnnqi0sb1vi0iqezqxsmc8moc.pngРезультаты измерений 4х дней. Яркость снижается вместе с зарядом батареек. Как оказалось при снижении напряжения питания, у нас пропорционально понижается напряжение, прикладываемое к датчику яркости и как следствие измеренная яркость тоже. Но к счастью, зависимость во всем диапазоне входных напряжений от 3.3В до 2.5В оказалась линейной (в пределах допусков) и исправить проблему можно простой нормировкой результата измерения.z_7jnayod-zar-wbpjjtgfaxxsu.pngГрафик зависимости максимальной измеренной яркостивлажности в зависимости от заряда батареек Максимально возможное значение влажностияркости при текущем заряде батареи можно посчитать по формулам: q_w = (adcbattery * 4) / 15; // влажность почвы q_l = (adcbattery * 25) / 101; // яркость Чтобы учесть возможные погрешности (и случайные всплески) измерений АЦП был реализован простейший медианный фильтр. Делаем три замера с небольшим интервалом, далее с помощью алгоритма быстрой сортировки (спасибо Википедия) находим среднее значение и его принимаем за результат.

float adcRead[3]; void quickSort(float *s_arr, int first, int last){   if (first < last){       int left = first, right = last, middle = s_arr[(left + right) / 2];       do{         while (s_arr[left] < middle) left++;         while (s_arr[right] > middle) right--;         if (left <= right){           int tmp = s_arr[left];           s_arr[left] = s_arr[right];           s_arr[right] = tmp;           left++;           right--;         }       }        while (left <= right);       quickSort(s_arr, first, right);       quickSort(s_arr, left, last);   } }  void analogReadMedian(){   adcRead[0] = analogRead(ADCPin);   delay(10);   adcRead[1] = analogRead(ADCPin);   delay(10);   adcRead[2] = analogRead(ADCPin); }  void readADC_median(int input){   switch(input){     case 1 :       digitalWrite(BPin, HIGH);       digitalWrite(C_DHTPin, LOW);       delay(50);       analogReadMedian();       quickSort(adcRead, 0, 2);       adcbattery = adcRead[1] * 4;       q_w = (adcbattery * 4) / 15;       q_l = (adcbattery * 25) / 101;        digitalWrite(BPin, LOW);       break;     case 2 :       digitalWrite(BPin, LOW);       digitalWrite(C_DHTPin, LOW);       analogWrite(PWMPin, 412);       delay(50);       analogReadMedian();       quickSort(adcRead, 0, 2);       adcwater = 5*(100 - 100*(adcRead[1] / q_w));       if (adcwater > 100) adcwater = 100;       if (adcwater < 0) adcwater = 0;       analogWrite(PWMPin, 0);       break;           case 3 :       digitalWrite(BPin, LOW);       digitalWrite(C_DHTPin, HIGH);       delay(50);       analogReadMedian();       quickSort(adcRead, 0, 2);       adclight = 100*(adcRead[1] / q_l);       if (adclight > 100) adclight = 100;       if (adclight < 0) adclight = 0;       break;     default :       delay(1);    } } 

Измерение влажности почвы

Для того, чтобы измерять влажность почвы, необходимо на земляной электрод подать напряжение и на другом его конце измерить сколько этого самого напряжения дошло, а сколько «потерялось» в почве. На практике оказалось, что при подаче «единицы» диапазон возможных значений на входе АЦП при нахождении электрода в очень сухой и очень влажной почве — совершенно незначителен, что-то около 100 мВ. Но у братьев из поднебесной было подсмотрено, что надо подавать ШИМ сигнал с частотой 100 кГц и скважностью 50% и в этом случае потери сигнала во влажной почве становятся весьма заметными. Максимальна частота ШИМ, на которую способен ESP8266 равна около 78 кГц, но как показала практика и при 75 кГц результаты измерений влажности достаточно точные и отражают состояние почвы. Чтобы активировать ШИМ надо:

//инициализируем GPIO на выход pinMode(PWMPin, OUTPUT);  //устанавливаем частоту ШИМ в Герцах analogWriteFreq(75000);  //включаем ШИМ, значение 512 соответствует скважности 50% analogWrite(PWMPin, 512); //Делаем замеры //выключаем ШИМ analogWrite(PWMPin, 0); 

Планы на будущее

В данный момент, если проводить все измерения 1 раз в минуту, то комплекта новых батареек (2 шт ААА) хватит на 4 дня или 5760 измерений. Если же делать по 12 замеров в день (раз в два часа), то батареек должно хватить на год как минимум (480 дней). Но время автономной работы можно еще увеличить, если включать WiFi не каждое «просыпание», а пару раз в день. Но, чтобы это реализовать надо каким то образом отличать одно включение от другого. Оперативная память для этого не годится, т.к. в режиме Deep sleep очищается. Для этой цели мог бы подойти EEPROM, однако на ESP он реализован как часть флеша и писать туда часто не самая лучшая идея (и не самая энергоэффективная). Но, не все так плохо и в нашем распоряжении еще есть 512 байт RTC памяти, которая прекрасно сохраняет данные в то время, пока чип находится в режиме Deep sleep. Я нашел для себя две новые функции и не успел еще их внедрить в проект.

ESP.rtcUserMemoryWrite(offset, &data, sizeof(data)) ESP.rtcUserMemoryRead(offset, &data, sizeof(data))

Также в ближайшее время будет добавлена самая важная функция, а именно отправка звуковых (бипером) и мобильных (пуш) уведомлений в случае высыхания почвы. Пока как то не до этого было. Самое важное, о чем надо не забыть, это учет текущего времени, чтобы не начать пиликать ночью.

Заключение

Проект целиком на гитхабе. Спасибо за внимание.rht7rrp3sw3ayupnnwzgwvgbdh4.jpegОтдельное спасибо моей жене за регулярный полив тестового цветка. PS. Будет и третья часть.Используемые источники:

  • https://sprut.ai/client/article/1500
  • https://mysku.ru/blog/aliexpress/44712.html
  • https://m.habr.com/ru/post/130421/

Рейтинг автора
5
Подборку подготовил
Максим Уваров
Наш эксперт
Написано статей
171
Ссылка на основную публикацию
Похожие публикации