CGI-X10

CGI-X10

From Bubba.org

Jump to: navigation, search

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.

Image:CGI-x10-ss1.jpg

An example of the "radio" format view

Image:CGI-x10-ss2.jpg

An example of adjusting the format on the command line, turning format output off (none).

Image:CGI-x10-ss3.jpg

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".