From 4e017cb3dbb9a476610e48f03c41344b6fd2e270 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Wed, 9 Mar 2011 02:26:31 +0100 Subject: [PATCH] Replace brmdoor.php by full-fledged universal hub script brmd brmd should handle various kinds of brmlab-related events (brmdoor unlocks, status panel events, wiki updates) and provide central place to handle them, with unified interface (web and IRC). Currently, all of this should be implemented, except wiki updates handling. But the script is still a bit rudimentary; some TODO items are mentioned in the TODO file. --- TODO | 33 +++++++ brmd.pl | 245 ++++++++++++++++++++++++++++++++++++++++++++++ brmdoor.php | 91 ----------------- status-closed.png | Bin 0 -> 1645 bytes status-open.png | Bin 0 -> 1762 bytes 5 files changed, 278 insertions(+), 91 deletions(-) create mode 100644 TODO create mode 100644 brmd.pl delete mode 100644 brmdoor.php create mode 100644 status-closed.png create mode 100644 status-open.png diff --git a/TODO b/TODO new file mode 100644 index 0000000..5c675de --- /dev/null +++ b/TODO @@ -0,0 +1,33 @@ +* Support for brmwiki update notifications. + Watch the RSS feed. + +* Potentially some prettier icons and richer javascript stubs. + + +* Have the brmlab sketch do bi-directional TCP communication. + Currently, it only sends stuff and cannot receive any + instructions. This is pre-req for features below. + Alternatively, we may decide we need to switch back to + USB communication (with reliable USB host) if the ethernet + shield proves to be too unreliable. + +* Way to override status from web page. + To keep status LED and web page in sync, bi-directional + communication will be required. + +* Way to unlock door remotely (through some secure channel). + Bi-directional communication will be required. + + +* Webcam support. + We will need to figure out where to connect it. + +* Picture snapshot support. + Add a button to the panel that will make the webcam + take a snapshot - useful for letting the world know + who came in, or to publish random stuff. Post to twitpic + or some-such. + +* Live-feed support. + Turn webcam on/off based on the second switch. Route the + stream to some public place. diff --git a/brmd.pl b/brmd.pl new file mode 100644 index 0000000..54e917c --- /dev/null +++ b/brmd.pl @@ -0,0 +1,245 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use POE qw(Component::IRC Component::Client::TCP Component::Server::HTTP); +use HTTP::Status qw/RC_OK/; + +our $channel = "#brmlab"; +our ($status, $record, $topic) = (0, 0, 'BRMLAB OPEN'); + +my $irc = POE::Component::IRC->spawn( + nick => 'brmbot', + ircname => 'The Brmlab Automaton', + server => 'irc.freenode.org', +) or die "Oh noooo! $!"; + +my $door = POE::Component::Client::TCP->new( + RemoteAddress => "192.168.1.3", + RemotePort => 23, + ServerInput => \&brmdoor_input, +) or die "Oh naaaay! $!"; + +my $web = POE::Component::Server::HTTP->new( + Port => 8088, + ContentHandler => { + "/brmstatus.html" => \&web_brmstatus_html, + "/brmstatus.js" => \&web_brmstatus_js, + "/brmstatus.png" => \&web_brmstatus_png, + "/" => \&web_index + }, + Headers => {Server => 'brmd/xxx'}, +) or die "Oh neee! $!"; + + + +POE::Session->create( + package_states => [ + main => [ qw(_default _start irc_001 irc_public irc_332 irc_topic) ], + ], + heap => { irc => $irc }, +); + +$poe_kernel->run(); + + +sub _start { + my $heap = $_[HEAP]; + + # retrieve our component's object from the heap where we stashed it + my $irc = $heap->{irc}; + + $irc->yield( register => 'all' ); + $irc->yield( connect => { } ); +} + +sub _default { + my ($event, $args) = @_[ARG0 .. $#_]; + my @output = ( "$event: " ); + + for my $arg (@$args) { + if ( ref $arg eq 'ARRAY' ) { + push( @output, '[' . join(', ', @$arg ) . ']' ); + } + else { + push( @output, "'$arg'" ); + } + } + print join ' ', @output, "\n"; +} + +sub status_str { + $status ? 'OPEN' : 'CLOSED'; +} + +sub record_str { + $record ? 'ON AIR' : 'OFF AIR'; +} + + +## Brmdoor + +sub brmdoor_input { + my $input = $_[ARG0]; + $input =~ /^(\d) (\d) (.*)$/ or return; + my ($cur_status, $cur_record, $brm) = ($1, $2, $3); + if ($cur_status != $status) { + $status = $cur_status; + my $st = status_str(); + $irc->yield (privmsg => $channel => "[brmstatus] update: \002$st" ); + my $newtopic = $topic; + if ($status) { + $newtopic =~ s/BRMLAB CLOSED/BRMLAB OPEN/g; + } else { + $newtopic =~ s/BRMLAB OPEN/BRMLAB CLOSED/g; + } + if ($newtopic ne $topic) { + $topic = $newtopic; + $irc->yield (topic => $channel => $topic ); + } + } + if ($cur_record != $record) { + $record = $cur_record; + my $st = record_str(); + $irc->yield (privmsg => $channel => "[brmvideo] update (TODO): \002$st" ); + } + if ($brm =~ s/^CARD //) { + print "from brmdoor: $input\n"; + if ($brm =~ /^UNKNOWN/) { + $irc->yield (privmsg => $channel => "[brmdoor] unauthorized access denied!" ); + } else { + $irc->yield (privmsg => $channel => "[brmdoor] unlocked by: \002$brm" ); + } + } +} + + +## Web interface + +sub disable_caching { + my ($response) = @_; + $response->push_header("Cache-Control", "no-cache, must-revalidate"); + $response->push_header("Expires", "Sat, 26 Jul 1997 05:00:00 GMT"); +} + +sub web_index { + my ($request, $response) = @_; + + my $sts = status_str(); + my $str = record_str(); + + $response->code(RC_OK); + $response->push_header("Content-Type", "text/html"); + disable_caching($response); + + $response->content(< +brmd + +brmlab +

brmd web interface

+

Enjoy the view!

+ + +EOT + ); + + return RC_OK; +} + +sub web_brmstatus_html { + my ($request, $response) = @_; + + my $bg = $status ? 'lightgreen' : '#DEE7EC'; + my $st = $status ? 'OPEN' : 'CLOSED'; + + $response->code(RC_OK); + $response->push_header("Content-Type", "text/html"); + disable_caching($response); + + $response->content(< +brmstatus + +

brmlab is $st

+ +EOT + ); + + return RC_OK; +} + +sub web_brmstatus_js { + my ($request, $response) = @_; + + $response->code(RC_OK); + $response->push_header("Content-Type", "text/javascript"); + disable_caching($response); + + $response->content(<; + close $img; + + $response->code(RC_OK); + $response->push_header("Content-Type", "image/png"); + disable_caching($response); + + $response->content($imgdata); + + return RC_OK; +} + + +## IRC + +sub irc_001 { + my $sender = $_[SENDER]; + + # Since this is an irc_* event, we can get the component's object by + # accessing the heap of the sender. Then we register and connect to the + # specified server. + my $irc = $sender->get_heap(); + + print "Connected to ", $irc->server_name(), "\n"; + + $irc->yield( join => $channel ); +} + +sub irc_public { + my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2]; + my $nick = ( split /!/, $who )[0]; + my $channel = $where->[0]; + + if ( my ($rot13) = $what =~ /^rot13 (.+)/ ) { + $rot13 =~ tr[a-zA-Z][n-za-mN-ZA-M]; + $irc->yield( privmsg => $channel => "$nick: $rot13" ); + } +} + +sub irc_332 { + my ($sender, $server, $str, $data) = @_[SENDER, ARG0 .. ARG2]; + $topic = $data->[1]; + print "new topic: $topic\n" +} + +sub irc_topic { + my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2]; + my $channel = $where; + $topic = $what; + print "new topic: $topic\n" +} diff --git a/brmdoor.php b/brmdoor.php deleted file mode 100644 index 29567b8..0000000 --- a/brmdoor.php +++ /dev/null @@ -1,91 +0,0 @@ - - - - -Brmdoor - - -

brmlab is

-
-> -> -
- - diff --git a/status-closed.png b/status-closed.png new file mode 100644 index 0000000000000000000000000000000000000000..cdd95bade1d2fc496e067d2a78e4b1cf76624e03 GIT binary patch literal 1645 zcmV-z29o)SP)J|hNJzXP#E<$=-ogV>)1o4!GO2i|5LA?gsIBe9NfeqyuIy~qYkTdT z-PxVF_wukao7r7EP7xAUI=VAw?w<3VpSgDy{?9|)?ZUHAXv0%++kOEl4{D`~O6ws@ zO2?9N#b~|YDRoM~%+s*;KLa=e6SigjM#DEsqoaEF7Y?N}yT?f63&eB7v}+r9i&r8L^0~61G+ct9-J4QmI#`K7ZI15FE z&cpRh7d3l{eaD`S<%@;G87Y6(pMh=({s_A>QZ5{Q<$F1~xC9%U1F4P9{kkwK18a#ymFz*&cut zJXI{@l~4-ZYWF&hM5(ukva1)OBa!rnIwd8l?IDCDmmSs~Jk|pc6XLt06ZT`+dj|leR5$WF0XEK`$E#L5y%LMzmMaJ$Hp4YGfPh=g zN+maxjH6qv9gXhfxCgY+z@MK-q|?OiAICKw0xCTKz@_@tYZF694r4Z*P6Gn&i4&dF z8iQXh<6Xawah&cB7xqfe?iblTd-RTjS(yw1K=BTsyu)3Xz5EwGCfUGucImz z{H3MN8?wz-+pp^f44=ud0=3K6HnlOQdH`IQ+1RXG?Zr><{uwq4-9+C5 zWDGK$z{Dhu+p>YPA%Fxp4mBafTg(5P_2qqIc(oeJb-SlqxbuagxV_c(Z_S}zh37+{ zj~&=U`GW;t8s3DGmwr`y|r5R z;YUP97vLByBgAW0-~FJGcz6<%jPDq|+5#pDu8qN@5~LoQVDWFWjuhh6=uzAQ08rQZ zCr;Cy{q*l2ddWv0z@!obsog62o@_;;C!JvE%LiF{Z?5gO+8@=m{waN9U~7L1cG)mr zDCI}Szjh?%oWF#>QtNHFEjm1^2e3;yh7Rv%`Mr5>vsznj!h>6V6K;97oPm1;oK2;Y zhxQ(QIAt0x%?sC2PIKGWFcfPzO=@x+k&5%_Uq5boZhNi`Pd*3Lt$b~JxV;9kF?dx9 z@nU|okQjO7ki>1#y19zK?x5Wk+EWm-kjVsAE=_DKkBnQ~I(Nmd-CFb7aPlPl;0!dj z^RpFz05ZT3kogWwPQ#D0@JKS1P}#9UDp|~852vw*l6X#&R;@vMb%XVrYfaB>S?h4_ zP59N@a0RFXPGsH@ARPb@pni2LBVP+y12hw%QN;oMTE)9ZBJ z_i)~%^Pf@OO$pL;zT3h~q=PvXNCJq{`CnlIqaNS_O*$zLC3L*m@BB^x(dV(iVG2kF rj^lye2K)#>8)yZN-9R_sG&=qR=b8{jvze+~00000NkvXXu0mjfkhc>` literal 0 HcmV?d00001 diff --git a/status-open.png b/status-open.png new file mode 100644 index 0000000000000000000000000000000000000000..c84e8d3771b29559c6201f98128bed398387644e GIT binary patch literal 1762 zcmV<81|9i{P)S6yE0F#m# zW?(hO%8dUxfGUD5n<*47S**G!+%SzmB@Lr8eig#OoVL)}56`i#up+I)pkz+KY%ev0i+g7c}s+S$OK z%f}T~*NzMVzgX3eh(rIa&Hy@foolFDCL$)MudexcFm%R~ zcEXPWJ+T(w^a8H^-6g5=vZFp5eO*JjAC(cPPa}E}BL_&_a*KZf;a2DD6Xw>5FzSo= zy)P%pv6sG|xo7+S>jnUD>!<%rsva7t@9fCMr*|0FF!*+4z`*XVqI|)%06vrl^zp|{Ja$u+ z4diZ<=x-Ba9%SI{DQ$lfaNuLa$7tLJMnHXsr4&^G6m30%={qQNEvFW1{j`_7WsyM| znA5mNq&VtB0J^byxK}$fme*^8K{G8E{*mJ1@eBBi!zFVIdj4I|1T;o{7Ks%^P#*y? z-~sK3D1pK`=s66$j>p+nHGZ<|-n+_goaLf5xy@d6Q|8|7hXIURJN;o7nV(CqNq2^y zYbasNf)u`h%x=gES^^511xY{);IpV}MUz(WS@2O24iBnD^$FMzl#I;Z+6G|84ao#` zzbp$XCeIFxdD^X={;;m9?Ir-au4ZrybtXuE#`GCmLfhGtynk$gOX~?+`#?{<@FEa_ zTF?;0c7%^FE-oFKI4F2X0;Jz~+}}2}+sIV7(67|8o&_mnBYdbc5POIf3Lfcu2ma_` z)w8F*5zP7P@48x}%WG(RP*2M{=QW8SH4qA}sIdd*iY|{mM7{&SL#6_aJ$m*`)@Djp zb~XPs0itu!NT29JzvtDwlvhG(Q1Ofl9`YUMU2u^1P|#vZ?p}%R-R*I@h(i028wQBh z*NnFkEDMY|EV=v--0M3cN%cZ{RYA}jVgm(_CLsj9k=}PerZ4{QuQ{Upk8RrRcFsPb z4RzzX0=S|exg=uDmrdnF;*&d<`h4_Q;QSH4YsYiir+*LAdw`W*m0&}}IkfEp{@5Y) zXV2utyZK4tngg3!O1Z`7{8xdiK1Q7a=*H^du42Y8MtzphXG`75rl*{9OHx60uxsI7 zfA;huJY!HT2O>4H&m`u#AdXg0lD-WwPnlAyjGF@c+lFcbBRi|Ct_t82`!!o$X_KbE zICHA$pjZE=e|yzdX#KR8akf?FZ)?+4wcRMAo6OyEsUm7Ftf_fK+mnUT+&aSanGhyt z-g*%DZl|8Uydl?6eQTJQU#XG3F4ku=^BNCaJ|SSe**NR@kMzIbdPD^Eac&E{pT)f1ehu$*^Nr4N)8f`lziPF6y>i1I05FOC=4Ju@36y;$I^vbj-~a#s07*qoM6N<$ Ef*u-ft^fc4 literal 0 HcmV?d00001