CGI-X10
From Bubba.org
Contents |
Introduction
CGI-x10 is a Perl/CGI interface to the BottleRocket X-10 Firecracker software. I wasn't impressed with the CGI interfaces that existed so I threw this together one evening. The code isn't as clean as is could be, but it gets the job done.
Features
- The same abilities as the x10 remote control
- Optional Select Boxes or remote control-like Radio Buttons (see screenshots)
- Remebers the last executed command
- Ability to turn off or on all items in a house
Requirements
- Script below (currently version 0.4)
- Bottlerocket (If you don't already have it, you will need it)
- If you would prefer a PHP interface as opposed to a perl interface, Eric Thelin's port of CGI-x10 perl to PHP can be found here.
Script
#!/usr/bin/perl # CGI-x10 # By Brian Wilson <bubba@bubba.org> (http://bubba.org/?option=cgi-x10) # Perl/CGI Based on x10 firecracker interface # - Requires Bottlerocket v0.04 or greater available here: # http://mlug.missouri.edu/~tymm # - Requires webserver with cgi enabled. # - Requires access to com port for webserver user (usually nobody) # # v0.4 (7/20/99) - Initial Release # $format="radio"; # set this to "select" for pulldown boxes or "radio" # for radio buttons # This field is also changable by passing # format to the script as seen in the examples below $exec="/usr/local/bin/br"; # location of your br binary # make sure the com port that br uses has # permission for anyone to use it $dimlevel="1"; # valid numbers are 1-6 (1 being slight dim, 6 being full # dim # Command-line usage: # You can also call this script via html links with commands like below: # http://mysite/cgi-bin/x10.pl?home=K&number=2&command=ON&format=radio # - This would turn K2 On # http://mysite/cgi-bin/x10.pl?home=K&command=AON&format=none # - This would turn on all devices in home K # Valid commands are AON AOFF DIM BRIGHT ON OFF LOFF LON # Valid homes are A-P # Valid numbers are 1-16 # Valid formats are radio, select, and none (for html links only) # - format defaults to the value set above # Valid dimlevel is 1-6 ################## Please don't edit beyond this point ##################### $version="0.4"; %FORM=(); &ReadParse; %command_list=("ON" => "On", "DIM" => "Dim", "OFF" => "Off", "BRIGHT"=> "Brighten", "AOFF" => "All Off", "AON" => "All On", "LON" => "Lamps On", "LOFF" => "Lamps Off"); &header; &homes; &numbers; &commands; &footer; if (($FORM{'command'} eq "AOFF") && ($FORM{'home'} =~ /^\S$/)) { &do_exec("-c $FORM{'home'} -F"); } elsif (($FORM{'command'} eq "AON") && ($FORM{'home'} =~ /^\S$/)) { &do_exec("-c $FORM{'home'} -N"); } elsif (($FORM{'command'} eq "LOFF") && ($FORM{'home'} =~ /^\S$/)) { &do_exec("-c $FORM{'home'} -D"); } elsif (($FORM{'command'} eq "LON") && ($FORM{'home'} =~ /^\S$/)) { &do_exec("-c $FORM{'home'} -B"); } elsif ($FORM{'number'} && $FORM{'command'} && $FORM{'home'}) { $show_number=1; $housenum=$FORM{'home'} . $FORM{'number'}; if (($FORM{'number'} =~ /^\d{1,2}$/) && ($FORM{'home'} =~ /^\S$/) && ($command_list{$FORM{'command'}})) { # if ($FORM{'command'} eq "DIM") { &do_exec("-c $FORM{'home'} -d -$dimlevel,$FORM{'number'}"); } elsif ($FORM{'command'} eq "BRIGHT") { &do_exec("-c $FORM{'home'} -d +$dimlevel,$FORM{'number'}"); } else { &do_exec("$housenum $FORM{'command'}"); } } else { print "<tr><td bgcolor=808080><center><i><b>"; print "Error: Invalid Entry</td></tr>\n"; &print_ver; } } else { &print_ver; } sub do_exec { my($cmd)=@_; system("$exec $cmd"); print "<tr><td bgcolor=808080><center><i><b>"; if ($show_number) { print "$command_list{$FORM{'command'}} for $housenum"; } else { print "$command_list{$FORM{'command'}} for $FORM{'home'}"; } print "</td></tr>\n"; &print_ver; } sub footer { if ($format ne "none") { print "<td><input type=submit value=Execute></td></tr></table>"; } print "</form><table border=2>"; } sub header { print "Content-type: text/html\n\n"; print "<HTML><head><title>CGI-x10</title></head>"; print "<body bgcolor=FFFFFF><form mode=POST><center>\n"; if ($FORM{'format'}) { $format=$FORM{'format'}; print "<input type=hidden name=format value=$format>\n"; } if ($FORM{'dimlevel'}) { $dimlevel=$FORM{'dimlevel'}; print "<input type=hidden name=dimlevel value=$dimlevel>"; } print "<br><table border=5>"; } sub commands { print "<td>"; if ($format eq "select") { print "<select name=command>"; foreach (sort keys %command_list) { if ($_ eq $FORM{'command'}) { print "<option selected value=$_>$command_list{$_}"; } else { print "<option value=$_>$command_list{$_}"; } } print "</select>"; } elsif ($format eq "radio") { foreach (sort keys %command_list) { if ($_ eq $FORM{'command'}) { print "<input checked type=radio name=command value=$_>$command_list{$_}"; } else { print "<input type=radio name=command value=$_>$command_list{$_}"; } print "<br>"; } } print "</td>"; } sub numbers { print "<td>"; if ($format eq "select") { print "<select name=number>"; for (1..16) { if ($_ eq $FORM{'number'}) { print "<option selected value=$_>$_"; } else { print "<option value=$_>$_"; } } print "</select>"; } elsif ($format eq "radio") { for (1..16) { if ($_ eq $FORM{'number'}) { print "<input checked type=radio name=number value=$_>$_"; } else { print "<input type=radio name=number value=$_>$_"; } print "<br>"; } } print "</td>"; } sub homes { print "<tr><td>"; if ($format eq "select") { print "<select name=home>"; foreach (A..P) { if ($_ eq $FORM{'home'}) { print "<option selected value=$_>$_"; } else { print "<option value=$_>$_"; } } print "</select>"; } elsif ($format eq "radio") { foreach (A..P) { if ($_ eq $FORM{'home'}) { print "<input checked type=radio name=home value=$_>$_"; } else { print "<input type=radio name=home value=$_>$_"; } print "<br>"; } } print "</td>"; } sub ReadParse { foreach (@_) { $_=~s/\r\n/ /g; } (*FORM) = @_; local ($request_method, $query_string, @key_value_pairs, $key_value, $key, $value); $request_method = $ENV{'REQUEST_METHOD'}; if ($request_method eq "GET") { $query_string = $ENV{'QUERY_STRING'}; } elsif ($request_method eq "POST") { read(STDIN,$query_string,$ENV{'CONTENT_LENGTH'}); } else { print "Content-type: text/html\n\n"; print "ERROR: Unsupported return method.\n"; exit(0); } @key_value_pairs = split(/&/, $query_string); foreach $key_value (@key_value_pairs) { ($key,$value) = split(/=/, $key_value); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; $value =~ s/~!/ ~!/g; # Stop shell-outs $value =~ s/\W/_/g; # convert non-alphas for security if (defined($FORM{$key})) { $FORM{$key} = join(",",$FORM{$key}, $value); } else { $FORM{$key} = $value; } } } sub print_ver { print "<tr><td bgcolor=008080>CGI-x10 v$version by "; print "<a href=\"mailto:bubba\@bubba.org\">Brian Wilson</a>"; print "</td></tr></table></html>\n"; }
Installation / Troubleshooting
- Edit x10.pl and change necessary values (including your perl location).
- Copy x10.pl to your cgi-bin directory, and give it execute permissions.
- Also, make sure that it can access your com-port as a non-privaleged user (most importantly, as the user that your httpd server runs as).
That should be it. If this doesn't work, make sure the Bottlerocket utilities work on the command-line. If they do not, then you have other problems. If the utilities work from the command-line and CGI-x10 still does not work, check the permissions on your com-port that Bottlerocket is using. Also, make sure that x10.pl is pointing to the correct version of Bottlerocket (configurable in the x10.pl script).
Changes
0.1 - 7/10/99
- Inital Release
0.2 - 7/11/99
- If format is set on command line, it will remeber
the format after the next execution.
- Cleaned up code a bit
- Added Lamps on/Lamps off
- Dim/Bright level can be set in script or on command line
0.3 - 7/17/99
- Various small fixes
0.4 - 7/20/99
- Security fixes
More closely check variables to make sure we are getting
somewhat valid data (hopefully elliminating no shell outs).
(Thanks to William McVey [wam@sa.fedex.com]> for the bug
reports)
- Minor HTML errors fixed (Thanks again William)
Screenshots
An example of the "select" format view.
An example of the "radio" format view
An example of adjusting the format on the command line, turning format output off (none).
Disclaimer
It is recommended that you run this program from a access protected directory on your webserver to prevent the general public from turing your devices on and off. This software is "use at your own risk".


