- PVSM.RU - https://www.pvsm.ru -
Добрый день, уважаемыее. В этой статье я несколько отойду от своего традиционного подхода к DYI – нашей основной целью станет быстрое и эффективное получение результата, а не изобретение велосипедов с целью самообучения, поэтому даже люди, впервые держащие паяльник, смогут все это повторить и получить готовое устройство за ~1000 рублей и один день.
Говорят, лень – двигатель прогресса. Это, в принципе, верное высказывание – лично меня всегда напрягала необходимость вставать и идти гасить свет, когда уже почти заснул. Поэтому еще на втором курсе университета я собрал простое устройство на AVRке, позволяющее включать и выключать люстру с помощью любого пульта дистанционного управления. Оно до сих пор висит в одной комнате и работает в режиме 24/5 уже 5 лет.
После была попытка избавиться от пульта – система распознавания голосовых команд, на такой же AVRке, которую я заодно сдал как курсовую в универе – она даже заработала, но не настолько удовлетворительно, как хотелось бы, поэтому менять шило на мыло я не стал.
Через некоторое время сформировалось понимание, что в подавляющем большинстве случаев, когда мне требуется включить или выключить свет, у меня в пределах досягаемости и непосредственной близости имеются либо ПК, либо планшет, либо коммуникатор – следовательно, наиболее удобным способом будет управление через них.
Я набросал вариант реализации на специальных радиомодулях, NRF24L01P [1] – действительно потрясающих, так, например, размер SMD-варианта этого модуля составляет всего 10х15 мм! При этом ими удобно управлять, у них есть собственный протокол, который хендлит адресацию, мультиприем, авто-подтверждение приема и т.п.
Соответственно, по моим прикидкам, должен был быть какой-то USB-донгл с этим модулем, в перспективе – подключенный к компьютеру с веб-сервером, чтобы дать возможность управлять с мобильных устройств, и исполнительные девайсы с ответными трансиверами.
Очень долго у меня не доходили руки до всех этих систем – уже год у меня из стены торчали провода, которые я каждый раз замыкал руками, включая люстру, и говоря себе «ну вот разгребу дела на работе, и сяду разведу платы».
К счастью, последние проекты на работе были связаны с мобильными устройствами, которые должны были уметь несколько больше, чем может дать STM32 и любой другой Cortex M3, и я достаточно много времени провел работая с OpenWRT и устройствами типа всеми любимого TL-MR3020 и TL-WR703, о настройке которых я недавно написал статью [2]. Вместе с этим опытом пришло осознание того, что подобные задачи решаются невероятно быстро и очень эффективно при помощи устройств с linux и wi-fi на борту. Хотя бы потому, что Wi-Fi дает куда более удобные (а в случае с необходимостью передачи видео/аудио – практически единственные доступные) средства беспроводной связи, поддерживаемые всеми современными устройствами.
Конечно, если объектов управления десятки, имеет смысл сделать более тупые исполнительные устройства на кастомных модулях, и оставить серверам с линуксом роль узлов. Но в случае, когда мы делаем продукт для реального использования у себя дома, а не в расчете на гипотетические объекты, такой подход приведет только к жуткой потере времени и денег.
Итак, давайте соберем за день устройство, которое позволит включать-выключать бытовой прибор (до 1.6КВт потреблением) по Wi-Fi, с красивым фронтэндом и без долгой возни с платами, прошивками и драйверами.
Начнем, вопреки традиции, не с железа, а с программной части, ибо она достаточно простая и проверить ее вы сможете сразу же после покупки роутера, даже без его разборки.
Надеюсь, к этому моменту вы уже успели купить TL-MR3020 и, может быть, даже прочитали мою статью по пересборке ядра. На самом деле, можно обойтись даже без пересборки, просто перешейте его прошивкой с официальной вики проекта OpenWRT – если потом возникнет желание, вы легко сможете сделать свою прошивку, встроив в нее необходимые скрипты.
Итак, как будет устроен наш прибор?
Давайте начнем. На данный момент вы должны уже перешить роутер на OpenWRT и подключиться к нему по Ethernet-кабелю.
Заходим по SSH/WinSCP на роутер и идем в /etc
для этого идем в /etc/config/network и пишем там
config interface 'wlan'
option proto 'dhcp'
Это обеспечит получение wi-fi контроллером роутера IP от DHCP нашего домашнего раздатчика вай-фай в лице другого роутера.
В /etc/config/wireless заботливые first-start скрипты уже сгенерили настройки радио, осталось закомментить строку #option disabled 1 включая модуль wi-fi и в секции ниже, описателе интерфейса, написать что-то типа
config wifi-iface
option device radio0
option network wlan
option mode sta
option ssid тут-имя-вашей-точки
option encryption psk2
option key тут-ваш-пароль
Данные настройки приведены для WPA2-PSK. Для WPA-PSK encryption будет psk, для открытой точки none, для вепа, соответственно, wep – более подробно лучше прочитать на официальной вики тут [3] и тут [4].
Проверяем что все хорошо при помощи
wifi down
wifi
iwconfig wlan0
Если все ОК, iwconfig сообщит вам что вы присоединены к вашей точке доступа, после чего от эзернета его следует отрубить и продолжить настройку по wi-fi.
Теперь нам надо дать доступ к GPIO пинам из юзер-спейса. Ядро это умеет само по себе, ничего делать для этого не нужно, но GPIO уже захвачены драйвером мигания светодиодами. При желании можно не трогать светодиоды и их драйвер, так как, согласно вики [5], есть несколько незадействованных GPIO, подтянутых к земле, подтяжку которых можно отпаять, после чего использовать их в собственных целях. В этом случае выгружать драйвер не нужно, достаточно только экспортировать GPIO (показано ниже). Но мы воспользуемся пинами со светодиодами, чтобы сразу увидеть результат трудов:
Пишем в /etc/rc.local
rmmod leds_gpio
echo 0 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio0/direction
echo 0 > /sys/class/gpio/gpio0/value
Этим мы выгружаем драйвер, захвативший ресурсы, после говорим, что хотим использовать в юзерспейсе пин 0, настраиваем его на выход и выводим туда 0, выключая светодиод. Теперь зажечь его можно командой
echo 1 > /sys/class/gpio/gpio0/value
А погасить – вот этой:
echo 0 > /sys/class/gpio/gpio0/value
Только не забываем, что наш скрип еще не выполнился, поэтому сначала перезагрузим роутер командой reboot, заодно проверив как после перезагрузки поднимается wi-fi.
Если вы пересобрали ядро и встроили в него mini-httpd, то переходите сразу к настройке, если нет — ставим его из репозитория
opkg update
opkg install mini-httpd
Теперь внесем небольшие правки в /etc/mini-httpd.conf, так чтобы его первая строка выглядела как
cgipat=cgi-bin/**.sh
Теперь сервер будет пинать все что лежит в /www/cgi-bin/ и чье имя оканчивается на .sh как команду, транслируя ее ответ браузеру.
На случай если нам не захочется тянуться к wi-fi, повесим дублирующее действие на единственную кнопку: в /etc/hotplug2.rules убираем галочку перед словом buttons, чтобы нажатие на кнопки вызывало скрипты-обработчкики из соответствующей папки, строка теперь должна выглядеть так:
SUBSYSTEM ~~ (^net$|^input$|button$|^usb$|^ieee1394$|^block$|^atm$|^zaptel$|^tty$) {
После этого идем в /etc/hotplug.d/, создаем там папку button, а в ней – скрипт buttons (не забывая выставить ему права на выполнение командой chmod +x buttons!) со следующим содержимым:
#!/bin/sh
if [ "$BUTTON" = "wps" ]; then
if [ "$ACTION" = "released" ]; then
state=`cat /sys/class/gpio/gpio0/value`
if [ "$state" = "0" ]; then
echo 1 > /sys/class/gpio/gpio0/value
else
echo 0 > /sys/class/gpio/gpio0/value
fi
fi
fi
Теперь нажатие на кнопку будет переключать состояние светодиода. При желании можно сделать чтобы светодиод под этой кнопкой светился в противофазе с управляющим, то есть чтобы при погашенной люстре кнопка аппаратного включения была подсвечена для упрощения ее поиска в потемках – для этого просто экспортируйте пин 26 в rc.local также, как экспортировали пин 0, и добавьте аналогичные строки вывода 1/0 в его value рядом с выводом в value нулевого пина.
Это можно проверить прямо сразу – если вы все сделали правильно, то нажатие на кнопку вызовет изменение состояния светодиода.
Теперь покидаем /etc и идем в /www, где создаем директорию cgi-bin, а в ней – скрипт light-control.sh, которому делаем chmod +x, со следующим содержимым:
#!/bin/sh
echo "content-type: text/html"
echo ""
input=$(echo $QUERY_STRING | tr "&" "n")
for param in $input
do
name=`echo $param | cut -f 1 -d "="`
value=`echo $param | cut -f 2 -d "="`
if [ "$name" = "action" ]; then
if [ "$value" = "on" ]; then
echo 1 > /sys/class/gpio/gpio0/value
elif [ "$value" = "off" ]; then
echo 0 > /sys/class/gpio/gpio0/value
fi
fi
done
cat /sys/class/gpio/gpio0/value
Первые две строки после #!/bin/sh обязательны для CGI-скрипта – говорим браузеру что все ок и мы сейчас выдадим хтмл, после чего шлем два rn в соответствии с требованиями стандарта.
Потом берем из переменной $QUERRY_STRING параметры, куда их поместил заботливый mini-httpd, и разбираем каждый на name и value. Вообще, тут будет использоваться только один параметр, но пусть код будет в более общем виде, на случай если решим расширить.
Дальше проверяем – если нам передали action=on, то зажигаем диод, если action=off – гасим.
А после всегда возвращаем то, что прочитали из value – 1 если диод горит, 0 – если нет. Таким образом, если мы дернем наш скрипт извне с каким-либо параметром кроме action=on/off или вообще без параметра, мы получим от него текущий статус светодиода.
Кидаем в директорию /www скаченный с офф. сайта jquerry [6] — с ним действительно удобно делать аяксовые запросы – я видел все эти java-script’ы впервые в жизни (т.к. это самая дальняя от моих занятий и интересов область), но за 5 минут при помощи гугла осилил нужные мне действия. Сохраняем jquerry под именем jquerry.js
Туда же сохраняем представленные ниже картинки под именами lamp_on.jpg и lamp_off.jpg, символизирующие нашу люстру – их сделал из стащенной с гугла картинки путем разрезания ее на две части и легкой подгонки по размеру друг к другу. При желании можно использовать любые картинки.
Там же создаем index.html, в который пишем
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
function LampImgOn()
{
$('#lamp_off').hide();
$('#lamp_on').show();
}
function LampImgOff()
{
$('#lamp_on').hide();
$('#lamp_off').show();
}
function ProcessResult(data)
{
if(data=="1n")
LampImgOn();
else
LampImgOff();
}
$(document).ready(function()
{
$.ajaxSetup({
cache: false
});
$('#lamp_on').hide();
jQuery.get('/cgi-bin/light-control.sh', {'action': 'none'}, ProcessResult);
$('#lamp_on').click(function()
{
jQuery.get('/cgi-bin/light-control.sh', {'action': 'off'});
LampImgOff();
})
$('#lamp_off').click(function()
{
jQuery.get('/cgi-bin/light-control.sh', {'action': 'on'});
LampImgOn();
})
window.setInterval("jQuery.get('/cgi-bin/light-control.sh', {'action': 'none'}, ProcessResult)",2000);
});
</script>
</head>
<body bgcolor="#000000">
<img id = 'lamp_off' src = 'lamp_off.jpg' height = '40%' style='display:none'>
<img id = 'lamp_on' src = 'lamp_on.jpg' height = '40%' style='display:none'>
</body>
</html>
Тут мы на размещаем на страничке две изначально невидимые картинки с зажженной и погашенной лампой, а ява-скрипт после старта запрашивает аяксом от CGI (при помощи параметра action=none) текущий статус, а результат передаем на ProcessResult, который активирует ту или иную картинку. Эта же функция зовется после асинхронных запросов на переключение статуса (которые выполняются в обработчиках события клика на картинки), а также заводится таймер, которые каждые 2000 мс дергает скрипт на предмет статуса, чтобы отображать актуальные данные в случае, когда кто-то изменил их с другой страницы или аппаратной кнопкой.
Вот, собственно, и все – теперь можно зайти браузером на IP нашего роутера и насладиться красивой страничкой, управляющей светодиодом. Если вы нажмете на кнопку роутера при открытой страничке и подождете 2 секунды, картинка изменится сама за счет запроса, выполненного таймером.
На этом программная часть закончена, переходим к железке.
Что касается аппаратной части, то тут ситуация двоякая. Собственно схема у нас простейшая – управляющая цепь твердотельного реле по сути – тот же светодиод, и все что нужно – обеспечить протекание через него достаточного для включения тока. У S202S02 это не меньше 8 мА.
К сожалению, напрямую завести его от GPIO не получится – напряжение на GPIO 2.6В, после чего стоит резистор в очень маленьком корпусе номиналом 260 Ом и светодиод с падением напряжения около 1.5В. Таким образом, через него течет около 4-5 мА. Падение на S202S02 от 1.2 до 1.4В, так что то там будет примерно такой же. Можно, конечно, поискать резистор в таком же корпусе, но меньшего номинала, перепаять его, и нагрузить несчастный GPIO на 10 мА, но лучше пойти более простым путем – роль светодиода у нас исполнит переход база-эммитер NPN-транзистора, через который при падении в 0.75В потечет ток в 0.7 мА а в коллектор мы ему включим управляющую цепь реле.
Проблемы же состоят в другом. Их, собственно, две:
Что касается пункта 1. Текстолит, на котором выполнена схема, попросту говоря дерьмовый.
Дорожки и контактные площадки срывает моментально, припой – подстать текстолиту – начинает плавиться когда этот самый текстолит уже начинает гореть.
Что касается пункта 2. Будь корпус на 5 мм выше – проблем бы не было. Но увы, конденсаторы блока питания и импульсный трансформатор слишком высоки, чтоб корпус закрылся.
К сожалению я не нашел какого-то идеального волшебного решения, позволяющего красиво и быстро запихать в корпус невпихуемое. Костыльных вариантов много – начиная от покупки пластикового корпуса, в который это все влезет (нормальный, в общем-то, вариант), и заканчивая синей изолентой и резиночками для удержания в целости исходного корпуса.
Я выбрал нечто среднее – т.к. у меня оставался полиморф-пластик, я проложил узкую его полоску по периметру исходного корпуса и вдавил в нее крышку.
Так что в этом вопросе я рекомендую каждому найти устраивающее его решение самостоятельно. Разумеется, если вы будете использовать большой корпус, либо приделаете БП вне этого мелкого, вам совсем не обязательно отпаивать от платы разъемы, я просто расскажу что сделал я.
Чтобы плата могла влезть в корпус вместе с блоком питания, я отпаял от нее все разъемы (Ethernet, USB-Host, micro-USB-Power), а также развязку от эзернета. Плата резко стала плоской. Если будете это делать – будьте очень, очень внимательны. Я поплатился за свою невнимательность, установив слишком сильный поток из фена, в результате чего отпаялся критичный конвертер U5, дающий 3.3 В системе. Более того, его сдуло на пол и пришлось его долго искать – но, к счастью, удалось припаять его обратно.
Обращаем внимание на перемычку R113 (обведена красным) – по умолчанию она разомкнута. Замкнув ее мы сможем подавать питание на роутер через разъем USB-Host – а туда подпаяться на порядок удобнее и надежнее, т.к. он не SMD. Поэтому замыкаем R113 и спокойно паяем два провода для питания в отверстия из-под разъема.
Заметили, как тяжело паять провод в «земляное» отверстие? Оно соединено с полигонами земли на всех слоях, где они есть – теплоотвод бешеный, мой паяльник еле справился.
А вот так выглядят внутренности блока питания (рядом с платой роутера для масштаба)
Отпаиваем два хилых провода, которые раньше шли к вилке, и припаиваем туда что-то более надежное, что потом соединим с сетью 220В. Заодно отпаиваем его USB-разъем, так как соединим его напрямую с нашими проводами питания роутера.
Готовим реле, паяя так, чтобы потом силовые провода ничего не коснулись. Я подпаял вот так:
После пайки запихиваем в термоусадку, либо заматываем изолентой, либо покрываем сверху каким-нибудь герметиком или чем-то аналогичным (кстати, на фото блока питания видно этот самый герметик — он был изначально, китайцы тоже заботятся о ТБ).
Далее паяем транзистор – Я взял первый попавшийся под руку 2N6517 и подпаял его базой к той площадке, где у LED4 было написано +, эммитером – ко второй.
Так вот. Так делать не надо. Потому что достаточно одного неверного движения и вы сорвете обе площадки, придется потом паяться к резистору. Лучше подпаяйте тоненькие проводки к обеим площадкам, закрепите их на плате и выведите в безопасное место. И – да – если вы будете паять неаккуратно, то рискуете, как я, коснуться паяльником выводов микросхемы памяти и закоротить их. После чего будете проклинать свои кривые руки и час пытаться очистить их оловоотсосами, оплетками для выпайки, иголками – проверено на себе. К счастью, очистить таки удалось, но напряжно было неимоверно.
Осталось совсем немного – теперь у нас есть выход типа «открытый коллектор» (оставшийся вывод транзистора), к которому паяем резистор из расчета падения 1.3 вольта на оптопаре – то есть, при питании от 3.3В (их проще всего взять, на нераспаяном разъеме P1 справа на рисунке выше это четвертый пин), мы должны обеспечить ток где-то в 10 мА, что означает ровно 200 Ом.
Теперь аккуратно кладем блок питания кондерами вниз на плату роутера, не забыв проложить бумажкой – металлический верх кондера не должен быть под напряжением, но перемкнуть что-нибудь может, так что пусть будет бумажка. Провода питания роутера запаиваем в отверстия от разъема USB на блоке, плюсовой пин реле припаиваем к 3.3В (отверстие 4 на P1), минусовой – через 200 Ом резистор к коллектору транзистора.
Спиливаем одну из бобышек крышки, чтобы она не упиралась в блок питания, выступ, предназначенный для нажатия на кнопку наращиваем при помощи обрезка стержня от ручки или того же полиморфа.
Ну и прижимаем это все крышкой, закрепляя ее как вам больше нравится – полиморфом, изолентой, резиночками – на что хватит фантазии и материалов.
Осталось подвести 220В к проводам питания роутера, а коммутируемые провода реле включить вместо выключателя люстры или любого другого бытового электроприбора.
Получилось? Поздравляю, теперь в вашей люстре есть веб-сервер с CGI под управлением Linux, отдающий пользователям веб-фронтэнд на JavaScript, и все это – примерно за 1000 рублей и один день возни.
Автор: Ariman
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/diy/20758
Ссылки в тексте:
[1] NRF24L01P: http://www.ebay.com/itm/2pcs-x-NRF24L01-SMT-1-27MM-wireless-module-Small-Size-Free-shipping-/160882335785
[2] статью: http://habrahabr.ru/post/158127/
[3] тут: http://wiki.openwrt.org/doc/uci/wireless
[4] тут: http://wiki.openwrt.org/doc/uci/wireless/encryption
[5] вики: http://wiki.openwrt.org/toh/tp-link/tl-mr3020#gpios
[6] jquerry: http://code.jquery.com/jquery-1.8.3.min.js
[7] Источник: http://habrahabr.ru/post/159745/
Нажмите здесь для печати.