Управляем светодиодами через WEB-интерфейс, или первый шаг к умному дому

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

Я уже рассказывал, что купил роутер. По причине того, что сейчас мне лень его ковырять мой WL-520GU на гарантии, он пока что будет работать вполне стандартно — главные герои сегодняшней затеи компьютер и нетбук. Роутер же будет всего лишь соединять их в сеть.

Итак, сегодня я хочу с нетбука, включенного в WLAN, управлять светодиодами на LaunchPad'e через WEB-интерфейс.

Как настоящий индеец, начну с конца, т.е., с прошивки контроллера. Логика ее работы сводится к приему байта через UART (использую свой софтовый UART) и включению светодиода, соответствующего принятой команде. Система команд гениально проста:

R — зажечь красный;
G — зажечь зеленый;
r — погасить красный;
g — погасить зеленый.

Собственно, код (писано в IAR):


#include "msp430g2231.h"
#include "ta_uart.h"

volatile unsigned char cmd_received=0;

void UART_RX_Handler(unsigned char ch)
{
  cmd_received=ch;
}

void Set15_25MHzClk(void)
{
  //Setting MCLK=SMCLK= ~15.25MHz
  BCSCTL1=RSEL3 | RSEL2 | RSEL1 | RSEL0;
  DCOCTL=DCO1 | DCO0;
}

void main(void)
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  
  Set15_25MHzClk();
  
  P1DIR=BIT0 | BIT6;
  P1OUT=0;
  
  UART_DefaultTimerConfig();
  
  UART_SetRxMode();
  
  UART_SetRxHandler(UART_RX_Handler);
  
  __enable_interrupt();
  
  while (1)
  {
    if (cmd_received=='R')
    {
      P1OUT|=BIT0;
      
      cmd_received=0;
    }
    
    if (cmd_received=='r')
    {
      P1OUT&=~BIT0;
      
      cmd_received=0;
    }
    
    if (cmd_received=='G')
    {
      P1OUT|=BIT6;
      
      cmd_received=0;
    }
    
    if (cmd_received=='g')
    {
      P1OUT&=~BIT6;
      
      cmd_received=0;
    }
  }
}


Со стороны ПК общаться с микроконтроллером будет программа на C, которую сервер (я не стал мудрить и выбрал Apache) будет вызывать как CGI-приложение.

CGI — волшебный интерфейс, дающий возможность пристыковать программу на любом языке к серверу. Условие только одно — язык должен поддерживать стандартные потоки ввода-вывода и переменные окружения. Взаимодействие происходит следующим образом: сначала клиент загружает HTML-страницу с формой. Я написал такую (писано в 1st Page 2000):


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
	<title>Remote LaunchPad LEDs control</title>
</head>

<body>

<h1 align="center">Remote LaunchPad LEDs control</h1>

<form method="get" action="http://192.168.1.2/cgi-bin/setled.exe">
<input type="hidden" name="mode" value="LED"\>
<input type="checkbox" name="R" value="on"/>Turn red LED on
<input type="checkbox" name="G" value="on"/>Turn green LED on
<input type="submit" value="Update LEDs"/>
</form>

</body>
</html>


— никаких красивостей, спартанская простота. Два чекбокса, каждый для своего светодиода, и кнопка отправки запроса. Когда мы кликаем на кнопку отправки, браузер посылает серверу запрос в адресной строке (при использовании метода GET; я выбрал именно его, ибо килобайты мне передавать не надо). Он выглядит как-то так:


http://192.168.1.2/cgi-bin/setled.exe?mode=LED&R=on&G=on


Или, например, так:


http://192.168.1.2/cgi-bin/setled.exe?mode=LED&G=on


Видно, что он содержит имена выбранных элементов формы и их значения. Сервер, получив запрос, кладет все, что правее знака "?" в переменную окружения QUERY_STRING и вызывает приложение, указанное в описании формы. Приложение читает QUERY_STRING, делает то, о чем его просили, и по мере необходимости пишет в stdout. Все, что приложение написало в stdout, сервер бережно перехватывает и отправляет клиенту.

Итак, код CGI-приложения (писано в Code::Blocks+MinGW, обычное консольное приложение, pure C):


#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

#include "PortDriver.h"

char success_htmsg[]={"\
<html>\
<body>\
<h2 align=center>Success!</h2>
\
<h5 align=center><a href=http://192.168.1.2/>Click here to go back</a></h5>\
</body>\
</html>"};

char fail_htmsg[]={"\
<html>\
<body>\
<h2 align=center>Failed to set LEDs state</h2>
\
<h3 align=center>Probably LaunchPad is not attached to PC.</h3>
\
<h5 align=center><a href=http://192.168.1.2/>Click here to go back</a></h5>\
</body>\
</html>"};

int main(void)
{
    HANDLE h;
    char *query;

    h=InitPort("\\\\.\\COM10",4800);
    query=getenv("QUERY_STRING");
    printf("Content-Type: text/html; charset=us-ascii\n\n");

    if (h==INVALID_HANDLE_VALUE)
    {
        printf("%s\n\n",fail_htmsg);

        return 0;
    }

    if (strstr(query,"R=on")!=NULL)
    {
        SendData(h,'R');
    }
    else
    {
        SendData(h,'r');
    }

    if (strstr(query,"G=on")!=NULL)
    {
        SendData(h,'G');
    }
    else
    {
        SendData(h,'g');
    }

    printf("%s\n\n",success_htmsg);

    return 0;
}


В его работе тоже все просто — открывается COM-порт (тут я тоже использую небольшой самописный модуль, который кочует у меня из проекта в проект), если порт открыть не получается, выдается сообщение (сформированная HTML-страница) об ошибке. В случае же успеха в строке запроса, переданной в QUERY_STRING, ищутся определенные параметры, после чего LaunchPad'у отправляется соответствующая команда, а клиенту сообщется, что все хорошо.

Тут кто-то может спросить — а где же те потоки, которыми я пугал общественность, описывая работу CGI, ведь везде обычные printf'ы? Все правильно. Дело в том, что обычный, родной и знакомый printf как раз и пишет в stdout. Только обычно stdout это консоль, а тут его перехватывает сервер. Так что никаких глобальных перемен не нужно. Т.е. все, что выведено с помощью printf'а, будет отдано клиенту в целости и сохранности — приложение просто выводит HTML-код страницы.

Собственно, программа кладется в директорию cgi-bin, HTML-страница с формой под именем index.html — в htdocs. LaunchPad втыкается в USB, и все начинает работать. Можно из другого конца квартиры включать/выключать светодиодики. Ну, или из другого конца мира, если пустить сервер в WAN. Но я не хочу, чтобы кто-то еще игрался с моими светодиодиками, и потому сервер смотрит исключительно в локалку. А на WiFi у меня WPA2 и фильтрация по MAC.

В аттаче лежат все файлы для желающих повторить мой подвиг.
  • +1
  • 07 августа 2011, 23:33
  • _YS_
  • 1
Файлы в топике: WiFi_LED.zip

Комментарии (35)

RSS свернуть / развернуть
А где-же ватные диски? :)

А вообще я расчитывал увидель wi-fi модуль + МК. Но и так неплохо
+1
Я леплю умный дом на ISM-передатчиках под 868, всяких плюшек из коробки нет конечно, зато дёшево и в пределах зоны квартира—лифты работает.
0
  • avatar
  • Dzhus
  • 08 августа 2011, 00:22
Оно что, к ПК подключается? Так неинтересно, раз уж на лончпаде есть USB-UART — втыкать его надо в роутер и программу писать под него же ;)
0
  • avatar
  • Vga
  • 08 августа 2011, 00:26
Wi-Fi не при делах чтоли?((( это по сути просто управление через UART. Все остальные промежуточные железячки всего лишь транспорт, а уже какой он там — пофиг, хоть спутниковая антенна или оптоволокно.
0
А где-же ватные диски?

Не сегодня. :-)

А вообще я расчитывал увидель wi-fi модуль + МК.

Не скрою, сначала я хотел делать именно так, и даже присмотрел модуль. Но зачем
плодить сущности? У меня есть WiFi роутер, есть нетбук, есть ПК. Зачем ставить
что-то еще? Ну, кроме соображений понтовости, естесственно. :-D

Я леплю умный дом на ISM-передатчиках под 868

Вот-вот. Для коммуникации между устройствами WiFi не нужен — это только front-end. А в самой back-end сети у меня тоже будут либо провода, либо RF, либо IR.

втыкать его надо в роутер и программу писать под него же

Именно так и будет! :-) Только никакого USB не надо (он пригодится для флешки), надо всего лишь распаять
штырьки штатного LVTTL UART'а. Вообще, смысл всех этих плясок — пощупать CGI в
спокойной обстановке. Пощупал, убедился, что ничего страшного там нет. Следующий
шаг — установка кастомной прошивки на роутер, а на нее lighttpd, например.
Сейчас я ищу версию, которая запустится на WL-520 — вчера зашил одну, так после
этого пришлось использовать аварийное восстановление; ситуация, в общем,
штатная, но кирпичиков отложил.

Wi-Fi не при делах чтоли?

А Вы ждали, что я сам соберу WiFi-модуль? :-D

Тем не менее, цель достигнута — светодиоды управляются без проводов, и
именно по WiFi. У такого решения есть масса преимуществ — не надо писать сервер
руками, не надо заботиться о безопасности (все уже готово), да и WiFi вообще
необязателен — подойдет что угодно. Расширяемость и гибкость, однако!

На сегодня я утвердился в мысли, что лучший front-end для умного дома — WEB-интерфейс.
Это позволит управлять им с любой кофеварки, имеющей WiFi и
браузер. Так что в плане следующее: на роутере будет поставлен сервер с CGI. CGI
— программа (или скрипт, подумаю) будет через UART сливать принятые сервером
параметры непосредственно на мозг (?) системы. Вообще же я пока не определился со
степенью разделения функциональности — может быть, на роутере будет вся логика,
а через UART будет подключаться всего лишь расширитель линий I/O. А может куплю
одноплатный комп на атоме, и просто подключу его в сеть (и на нем же подниму
сервер), а роутер, как и сейчас, будет работать штатно. Или будет какой-то
комбинированный вариант. Все это проясниятся, когда я таки расковыряю роутер и
поконкретнее определюсь с логикой работы умного дома.
0
  • avatar
  • _YS_
  • 08 августа 2011, 11:42
Я просто думал что используется WiFi модуль, готовый всмысле, а Вы расписали как его мучать)).
0
Только никакого USB не надо (он пригодится для флешки)
USB, если ты забыл — шина, и поддерживает подключение 127 устройств на один порт. Только нужен хаб.
Для коммуникации между устройствами WiFi не нужен — это только front-end.
В принципе, Wi-Fi тоже вполне годный вариант для связи устройств. Разве что он чуть сложнее и главное дороговат. Но и плюсы есть.
светодиоды управляются без проводов, и именно по WiFi
Это называается «формально правильно, но по сути издевательство». Ты просто управляешь СИДами через CGI. Конечно, каждый понимает, что кусок между браузером и сервером можно растянуть хоть вайфаем, хоть вообще из космоса им управлять через интернет. Но называть это «управление через вай-фай» — перебор. Ты и твоя статья к этому вайфаю отношения вообще не имеете.
Ну и кроме того, между сервером и собственно устройствами сеть тянуть все равно придется, на отдельной технологии. Например тех же проводах. Единственное, что дает перевод управления на сервер с веб-мордой — отвязку пульта. Но беспроводная сеть — это не только свободный пульт, но и простота развертывания. В текущем варианте ей и не пахнет.
P.S. UART я бы оставил роутеру. Для внешних коммуникаций предусмотрен USB, его и следует юзать. Можно конвертировать его в RS232/RS485/I2C/CustomRF/CustomIR, можно хоть во все это разом.
0
В принципе, Wi-Fi тоже вполне годный вариант для связи устройств.

Из пушки по воробьям, ИМХО. А для front-end — самое то. Обычная домашняя сеть + в ней сервер умного дома. Единообразие.

USB, если ты забыл — шина, и поддерживает подключение 127 устройств на один порт.

Не, не забыл. Только зачем все усложнять, если и там и так есть UART?

Можно конвертировать его в RS232/RS485/I2C/CustomRF/CustomIR, можно хоть во все это разом.

А драйверы CDC под тот линух, что на роутере, Вы мне напишете? :-) Доступная прошивка, насколько я помню, поддерживает только принтеры и mass storage.

Но называть это «управление через вай-фай» — перебор.

А я в заголовке называю это управление через WLAN. :-)

Ты и твоя статья к этому вайфаю отношения вообще не имеете.

Ну, как категорично. Я его использую. :-) Хотя, впрочем, я скорее всего добавлю спойлер в начале. А, может, и заголовок поменяю. Но это когда домой приду. :-)

В текущем варианте ей и не пахнет.

Текущего варианта еще нет. :-) Я уже говорил, что это было всего лишь освоение CGI.

UART я бы оставил роутеру.
0
UART я бы оставил роутеру.

Смысл? Он не задействован. Почему бы не использовать?
0
Из пушки по воробьям, ИМХО.
Зато включается в имеющуюся стандартную сетку и все такое. Удобно, короче. Ждем армов с Wi-Fi NIC за пару баксов, ага)
Только зачем все усложнять, если и там и так есть UART?
На мой взгляд красивее воспользоваться тем, что предусмотрено, чем выводить UART. Да и все равно прямо на роутер ничего вешаться скорее всего не будет. А значит весить на него нужно только гейт в сеть девайсов, и лучше беспроводной.
Кстати, тот же Lifelover прицепил управление сервами камеры на USB, а не UART, хотя в DIR-320 он наверняка есть где-то внутре.
А я в заголовке называю это управление через WLAN. :-)
Суть одна.
А драйверы CDC под тот линух, что на роутере, Вы мне напишете?
В прошивках вроде OpenWrt они уже есть. Хотя бы потому, что CDC девайсами представляются беспроводные мопеды.
0
Кстати, тот же Lifelover прицепил управление сервами камеры на USB, а не UART, хотя в DIR-320 он наверняка есть где-то внутре.
Кстати да) Не охота отвязывать ядро от уарта. В случае, если опять начнёт капризничать, уарт может ой как пригодиться)
0
В случае, если опять начнёт капризничать

Для этого случая на моем роутере есть волшебная кнопка аварийного бутлоадера. :-)
0
Зато включается в имеющуюся стандартную сетку и все такое.

Вот именно «все такое» и смущает. Вообще, в качестве стандарта для сетей типа «умного дома» принят LON.

На мой взгляд красивее воспользоваться тем, что предусмотрено, чем выводить UART.

Видимо, у нас с Вами разные представления о красоте. Что поделать, это обычное явление в нашем мире. Вот мне, например, нравятся девушки в очках. А Вам? :-D

Да и все равно прямо на роутер ничего вешаться скорее всего не будет.

Я собирался, вообще.

Суть одна.

Сейчас лучше? :-D
0
Красота технического решения — понятие таки более определенное. В том числе «ничего лишнего» и «комплектующие переделывать нежелательно» (последнее правило правда в радиокружке мне давали в более категоричной форме — готовые компоненты модификации не подлежат).
Опять же, если будет USB интерфейс — проще мигрировать на новую платформу, не факт, что этим всегда будет заниматься этот роутер.
Вообще, в качестве стандарта для сетей типа «умного дома» принят LON.
Линк? В вики с полпинка не нашел.
Сейчас лучше? :-D
Да, разумеется.
Я собирался, вообще.
Роутер — это такая штука, которая тихо висит в уголке рядом с розеткой 220 и розеткой с инетом. А системы УД расбросаны по всему дому, врядли какая-то из систем, кроме центрального контроллера сети, нужна там, где стоит роутер.
Необязательно даже возлагать задачу центрального контроллера на роутер. Вполне можно поставить выделенное устройство со своим веб-интерфейсом, включающееся в LAN/WLAN. В принципе, ресурсов у роутера не так много, их даже на основную задачу с трудом хватает, при большой нагрузке на сеть.
0
Линк?

ru.wikipedia.org/wiki/LonWorks
www.lon.ru/aboutlon.html

Да, разумеется.

Вот и славно. :-)
0
Скромненько там инфы.
Впрочем, насколько я понимаю, при желании эту сеть можно поднять и поверх IP/WiFi транспорта. Плюс вайфая в основном лишь в том, что девайсы интегрируются в уже имеющуюся сеть. А то я тока по своей квартире уже насчитываю десяток беспроводных коммуникаций различного типа, из них штук 5 в 2.4ГГц диапазоне и иногда друг другу мешают)
0
А драйверы CDC под тот линух, что на роутере, Вы мне напишете? :-)
Юзайте OpenWrt. Такая няшная штучка. Там драйверы хоть для паровоза.
0
Кстати, а блютус там есть? Вроде в обсуждении вогоплеера упоминали, что если найти модуль BT с UART-HCI интерфейсом, то можно легко поднять там БТ стек. А это вполне себе и инет для некоторых мобильных устройств (старых КПК с БТ, но без вайфая например), и PAN для умного дома.
В UART-HCI, думаю, мона попробовать перешить модулек БТ с дилэкстрима/гудлакбая.
0
Кстати, а блютус там есть?
Какие-то дрова точно есть)
0
Юзайте OpenWrt.


Я пока ореинтирусь на прошивку от Олега. Ибо на основе стандартных.
0
Зря)
0
Спасибо за статью, с CGI не был знаком, поэтому лично мне она полезна =)

Есть ламерский вопрос — какие функции используете для работы с COM портом(со стороны компа)?
0
какие функции используете для работы с COM портом(со стороны компа)?

WinAPI. Скачайте приложенный архив, там все исходники есть.
0
Спасибо, читаю на работе, не доглядел =)
0
Кстати, строго говоря, в программе для ПК есть ошибка — перед выходом дескриптор надо закрывать. Т.е., должно быть


...

CloseHandle(h);

return 0;



— я по запарке забыл это написать.

Но, в принципе, система сама освобождает ресурсы при завершении программы, так что работает и так. Но это некорректно, да.
0
  • avatar
  • _YS_
  • 08 августа 2011, 13:14
я понимаю что вы только CGI начали юзать, но на всякий случай предупрежу:
192.168.1.2/cgi-bin/setled.exe — не надо так делать, просто если проект выйдет из стадии «только для себя» надо будет это убрать :) например передавать во внутренний скрипт, там разбирать параметры и уже внутри него вызывать exe. так же страницу с ответом формировать внутри скрипта а не exe. от последнего требуется только код завершения работы, по которому определять что выводить.

Но думаю вы и сами до всего этого дойдете :)
0
Можно подробнее о причинах? В принципе, CGI не более чем интерфейс, и особой надобности в дополнительных прослойках нет. Хотя, на PHP и других специализированных языках писать конечно удобнее, а для хостера выгодно то, что скрипт на PHP легко загнать в песочницу. Но на своем сервере особой нужды в этом нет.
Хотя, с другой стороны, в ехе чуть проще оставить дырку для руткита, и сложнее ограничить песочницей.
0
ну можете считать меня параноиком, но при просмотре кода это сразу бросается в глаза, а значит атаковать будут скорее всего exe, а чем он там и с какими правами запущен (переполнение стека — любимая дырка у взломщиков)....., да наличие грамотно настроенных прав поможет, но:
передаваемые параметры парсятся внутри exe — это костыль, на мой взгляд. проще отпарсить их скриптом и передать в виде «setled.exe -LED_ON -R» — эти параметры очень легко получить внутри exe, их даже складывать никуда не нужно будет (особенности работы windows).
далее, не очень продуктивно выдавать ХТМЛ страницу из exe, банально неудобно, проще обработать ответ и отобразить необходимую страницу. Переписывать страницу проще, нет нужды перекомпиливать. опять же пока страница мала нет проблем с памятью и выводом, что будет при красивом большом сайте — не понятно. Там тоже по граблям можно походить.
Опять же повторюсь, пока это делаешь «для себя» и «по приколу» — все это не важно :)
0
Ничем это не грозит, абсолютно. Если настроено все нормально, то хоть exe хоть dll (что кстати сделано на ebay) все одно и тоже.
Просто следить за переполнением стека, утечкой памяти.
0
ответил выше
0
Я прочитал. У меня 5 лет назад был достаточно крупный проект и в нем как раз был exe cgi.
Неудобно если просто делать body="<кокой то тег>", а потом вывод body. Есть xml, использовать как метаданные.

Вот в чем реально неудобство, так это в необходимости повторной компиляции при небольших изменениях. Но опять же, если сделать как сделал я — использовать метаданные для формирования страничек, то всё можно описывать в xml, абсолютно всё.
Exe удобнее когда работаешь с оборудованием. Если банально веб страничка + БД, то лучше PHP, perl или руби, ну или подобный.))
0
соглашусь… еще можно прямо из экзешника читать страницу с жесткого диска и выводить её, опять же перекомпиляция потребуется только при смене имен страницы :) Ну вообще это все абстрактные и пока очень далекие вопросы, но задумться о них нужно уже на начальной стадии, дабы потом не пришлось переписывать кучу кода. Я стараюсь делать «модульные конструкции» т.е. когда при изменении какой-то одной или 2х вещей не приходитсмя переписывать весь проект. При таком подходе мы имеем избыточность кода, и возникновение подобных (очень далеких по перспективе) вопросов на начальной стадии (когда и других проблем хватает) но в конечном итоге это экономит время.
С другой стороны, при наличие хорошей защиты сети от внешней атаки, при условии что вы рулите только из дома, наличие фильтрации MAC адресов (чтоб к вам никто по вайфаю не залез) можно писать вообще как и что угодно… главное никому этого не показывать ;))
0
Согласен с Вами. У меня тоже все модульное. За все время уже накопилось много модулей, консольных утилит, соединив которые можно получить простые и надежные результаты.
0
Главное — не переусердствовать с модульностью. Я оформляю в модуль только то, что планирую использовать более чем в двух проектах. :-)
0
Это понятно, а то можно до крайности дойти. Ж-)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.