html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Собираем wi-fi устройство управления электроприборами с веб-сервером и JS-фронтэндом

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

Введение


Говорят, лень – двигатель прогресса. Это, в принципе, верное высказывание – лично меня всегда напрягала необходимость вставать и идти гасить свет, когда уже почти заснул. Поэтому еще на втором курсе университета я собрал простое устройство на AVRке, позволяющее включать и выключать люстру с помощью любого пульта дистанционного управления. Оно до сих пор висит в одной комнате и работает в режиме 24/5 уже 5 лет.
После была попытка избавиться от пульта – система распознавания голосовых команд, на такой же AVRке, которую я заодно сдал как курсовую в универе – она даже заработала, но не настолько удовлетворительно, как хотелось бы, поэтому менять шило на мыло я не стал.
Через некоторое время сформировалось понимание, что в подавляющем большинстве случаев, когда мне требуется включить или выключить свет, у меня в пределах досягаемости и непосредственной близости имеются либо ПК, либо планшет, либо коммуникатор – следовательно, наиболее удобным способом будет управление через них.
Я набросал вариант реализации на специальных радиомодулях, NRF24L01P – действительно потрясающих, так, например, размер SMD-варианта этого модуля составляет всего 10х15 мм! При этом ими удобно управлять, у них есть собственный протокол, который хендлит адресацию, мультиприем, авто-подтверждение приема и т.п.
Соответственно, по моим прикидкам, должен был быть какой-то USB-донгл с этим модулем, в перспективе – подключенный к компьютеру с веб-сервером, чтобы дать возможность управлять с мобильных устройств, и исполнительные девайсы с ответными трансиверами.
Очень долго у меня не доходили руки до всех этих систем – уже год у меня из стены торчали провода, которые я каждый раз замыкал руками, включая люстру, и говоря себе «ну вот разгребу дела на работе, и сяду разведу платы».
К счастью, последние проекты на работе были связаны с мобильными устройствами, которые должны были уметь несколько больше, чем может дать STM32 и любой другой Cortex M3, и я достаточно много времени провел работая с OpenWRT и устройствами типа всеми любимого TL-MR3020 и TL-WR703, о настройке которых я недавно написал статью. Вместе с этим опытом пришло осознание того, что подобные задачи решаются невероятно быстро и очень эффективно при помощи устройств с linux и wi-fi на борту. Хотя бы потому, что Wi-Fi дает куда более удобные (а в случае с необходимостью передачи видео/аудио – практически единственные доступные) средства беспроводной связи, поддерживаемые всеми современными устройствами.
Конечно, если объектов управления десятки, имеет смысл сделать более тупые исполнительные устройства на кастомных модулях, и оставить серверам с линуксом роль узлов. Но в случае, когда мы делаем продукт для реального использования у себя дома, а не в расчете на гипотетические объекты, такой подход приведет только к жуткой потере времени и денег.
Итак, давайте соберем за день устройство, которое позволит включать-выключать бытовой прибор (до 1.6КВт потреблением) по Wi-Fi, с красивым фронтэндом и без долгой возни с платами, прошивками и драйверами.

Программная часть


Начнем, вопреки традиции, не с железа, а с программной части, ибо она достаточно простая и проверить ее вы сможете сразу же после покупки роутера, даже без его разборки.
Надеюсь, к этому моменту вы уже успели купить TL-MR3020 и, может быть, даже прочитали мою статью по пересборке ядра. На самом деле, можно обойтись даже без пересборки, просто перешейте его прошивкой с официальной вики проекта OpenWRT – если потом возникнет желание, вы легко сможете сделать свою прошивку, встроив в нее необходимые скрипты.
Итак, как будет устроен наш прибор?

  1. Так как нам важно сохранить минимальное количество деталей, мы не будем использовать никаких внешних флешек и хабов, поэтому размер доступной нам памяти ограничен 4 МБ, из которых свободно, обычно, около 1-1.5 МБ.
  2. Учитывая пункт 1 выберем самый легковесный веб-сервер, поддерживающий CGI – идеальным вариантом стал 20-килобайтный mini-httpd безо всяких надстроек.
  3. В качестве cgi-скрипта воспользуемся обычными башевскими скриптами. В принципе, место позволяет поставить минимальную сборку питона. Правда, боюсь, без пересборки ядра вы это не осуществите – т.к. все, что вы ставите после прошивки устанавливается в JFFS, то и занимает оно намного больше, чем если бы было вбилдено изначально в SquashFS. В порядке эксперимента, я вбилдил и python-mini и mini-httpd прямо в образ, выкинув оттуда все лишнее – при билде JFFS образа система кинула эрроры о превышении размера, оставив на память недособранные куски, но SquashFS-образ собрался нормально, оставив мне еще ~250 КБ свободного места – для наших нужд вполне хватит. Еще одно замечание – старт питона с внутренней флешки выполняется намного медленнее, чем старт башевского интерпретатора (и явно медленнее, чем с внешней USB-флешки, сказывается SPI-интерфейс), поэтому при использовании питоновских скриптов для CGI отклик будет составлять около 1 секунды – не очень критично, но слегка раздражает. Впрочем, если бы я писал что-то более сложное, чем дрыганье одним GPIO, меня бы куда больше раздражал огромный и мерзкий баш-скрипт, и я бы предпочел смириться с секундным стартом интерпретатора питона
  4. Баш-скрипт будет дергать один из доступных нам GPIO, на котором висит светодиод. Светодиод мы с вами потом отпаяем и привесим на него твердотельное реле, управляющая цепь которого является по сути таким же светодиодом.
  5. Index.html будет содержать в себе небольшой js-код для отображения красивой картинки с лампочкой, которая будет зажигаться/гаснуть при нажатии, выполняя асинхронный запрос к CGI-скрипту, а также будет дергать его каждые N секунд, на случай если кто уже зажег лампочку с другого компьютера – чтобы обновить картинку в соответствии со статусом.
  6. Запитаем мы это все от идущего в комплекте блока питания, предварительно его разобрав, вынув из корпуса сам модуль, чтобы уменьшить размеры итогового девайса. Этот шаг опционален, если хотите – можете питать как вам удобнее.


Давайте начнем. На данный момент вы должны уже перешить роутер на OpenWRT и подключиться к нему по Ethernet-кабелю.
Заходим по SSH/WinSCP на роутер и идем в /etc

Настраиваем wi-fi

для этого идем в /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 – более подробно лучше прочитать на официальной вики тут и тут.
Проверяем что все хорошо при помощи

wifi down
wifi
iwconfig wlan0

Если все ОК, iwconfig сообщит вам что вы присоединены к вашей точке доступа, после чего от эзернета его следует отрубить и продолжить настройку по wi-fi.

Настраиваем GPIO

Теперь нам надо дать доступ к GPIO пинам из юзер-спейса. Ядро это умеет само по себе, ничего делать для этого не нужно, но GPIO уже захвачены драйвером мигания светодиодами. При желании можно не трогать светодиоды и их драйвер, так как, согласно вики, есть несколько незадействованных 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

Если вы пересобрали ядро и встроили в него 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 нулевого пина.

Это можно проверить прямо сразу – если вы все сделали правильно, то нажатие на кнопку вызовет изменение состояния светодиода.

Пишем CGI-скрипт

Теперь покидаем /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-скрипта – говорим браузеру что все ок и мы сейчас выдадим хтмл, после чего шлем два \r\n в соответствии с требованиями стандарта.
Потом берем из переменной $QUERRY_STRING параметры, куда их поместил заботливый mini-httpd, и разбираем каждый на name и value. Вообще, тут будет использоваться только один параметр, но пусть код будет в более общем виде, на случай если решим расширить.
Дальше проверяем – если нам передали action=on, то зажигаем диод, если action=off – гасим.
А после всегда возвращаем то, что прочитали из value – 1 если диод горит, 0 – если нет. Таким образом, если мы дернем наш скрипт извне с каким-либо параметром кроме action=on/off или вообще без параметра, мы получим от него текущий статус светодиода.

Пишем фронтэнд

Кидаем в директорию /www скаченный с офф. сайта jquery — с ним действительно удобно делать аяксовые запросы – я видел все эти java-script’ы впервые в жизни (т.к. это самая дальняя от моих занятий и интересов область), но за 5 минут при помощи гугла осилил нужные мне действия. Сохраняем jquery под именем jquery.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=="1\n")
					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. Нужно отпаять светодиод (у нас это светодиод LED4) и припаять вместо него наш транзистор
  2. Нужно как-то упихать в корпус реле (ну это нетрудно, оно мелкое) и внутренности блока питания.

Что касается пункта 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 рублей и один день возни.
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

105
    +87 surfers

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • casanova531
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции