Difference between revisions of "Install HTML"

From xPL
Jump to: navigation, search
(Install a web server)
Line 37: Line 37:
  
 
= CGI control script =
 
= CGI control script =
 +
 +
Create the home control directory:
 +
WWW_CONTROL=$WWW_ROOT/homeControl
 +
mkdir -p $WWW_CONTROL
 +
chmod -R 775 $WWW_CONTROL
 +
chown -R control:users $WWW_CONTROL
 +
cd $WWW_CONTROL
  
 
The following script can be run either from a terminal or as a [https://en.wikipedia.org/wiki/Common_Gateway_Interface Common Gateway Interface] (CGI) script:
 
The following script can be run either from a terminal or as a [https://en.wikipedia.org/wiki/Common_Gateway_Interface Common Gateway Interface] (CGI) script:
#!/usr/bin/perl
+
<pre>
use IO::Socket;
+
#!/usr/bin/perl
use CGI;
+
use IO::Socket;
my $cgi = CGI->new;
+
use CGI;
+
my $cgi = CGI->new;
#-------------------------------------------------------------------------------
+
 
# constants
+
#-------------------------------------------------------------------------------
#
+
# constants
my $portId = 3865;
+
#
my $messageType = 'xpl-cmnd';
+
my $portId = 3865;
my $source = 'sendstate.harmonia';
+
my $messageType = 'xpl-cmnd';
my $target = 'dspc-state.home';
+
my $source = 'sendstate.harmonia';
my $scheme = 'state.basic';
+
my $target = 'dspc-state.home';
+
my $scheme = 'state.basic';
$separator = '-' x 80;
+
 
$indent = ' ' x 2;
+
$separator = '-' x 80;
+
$indent = ' ' x 2;
#-------------------------------------------------------------------------------
+
 
# Input arguments
+
#-------------------------------------------------------------------------------
#
+
# Input arguments
my $verbose = 1;
+
#
my ($room, $kind, $object, $value);
+
my $verbose = 1;
my $broadcastAddress = '255.255.255.255';
+
my ($room, $kind, $object, $value);
my $timeout = -1;
+
my $broadcastAddress = '255.255.255.255';
my $logFilespec = '/tmp/sendState.log';
+
my $timeout = -1;
+
my $logFilespec = '/tmp/sendState.log';
if ($ENV{'REQUEST_METHOD'}) {
+
 
                                                        # get parameters from URL
+
if ($ENV{'REQUEST_METHOD'}) {
  $room  = $cgi->param('room');     
+
                                                      # get parameters from URL
  $kind  = $cgi->param('kind');     
+
  $room  = $cgi->param('room');     
  $object = $cgi->param('object');     
+
  $kind  = $cgi->param('kind');     
  $value  = $cgi->param('value');     
+
  $object = $cgi->param('object');     
}
+
  $value  = $cgi->param('value');     
else {
+
}
                                              # get parameters from command line
+
else {
  use Getopt::Std;
+
                                              # get parameters from command line
  my %opts;
+
  use Getopt::Std;
  getopts('hvb:t:l:', \%opts);
+
  my %opts;
 
+
  getopts('hvb:t:l:', \%opts);
  die("\n".
+
 
      "Usage: $0 [-hv] [-b address] [-t timeout] room kind object value\n".
+
  die("\n".
      "\n".
+
      "Usage: $0 [-hv] [-b address] [-t timeout] room kind object value\n".
      "Parameters:\n".
+
      "\n".
      "${indent}-h      display this help message\n".
+
      "Parameters:\n".
      "${indent}-v      verbose\n".
+
      "${indent}-h      display this help message\n".
      "${indent}-b addr broadcast address\n".
+
      "${indent}-v      verbose\n".
      "${indent}-t time timeout\n".
+
      "${indent}-b addr broadcast address\n".
      "${indent}-l file log filespec\n".
+
      "${indent}-t time timeout\n".
      "\n".
+
      "${indent}-l file log filespec\n".
      "The message is sent to machine <server>, UDP port <portId>.\n".
+
      "\n".
      "\n".
+
      "The message is sent to machine <server>, UDP port <portId>.\n".
      "More information with: perldoc $0\n".
+
      "\n".
      "\n".
+
      "More information with: perldoc $0\n".
      ""
+
      "\n".
      ) if ($opts{h});
+
      ""
  $verbose = $opts{v};
+
    ) if ($opts{h});
+
  $verbose = $opts{v};
  ($room, $kind, $object, $value) = @ARGV;
+
 
  $broadcastAddress = $opts{'b'} || $broadcastAddress;
+
  ($room, $kind, $object, $value) = @ARGV;
  $timeout = $opts{'t'} || $timeout;
+
  $broadcastAddress = $opts{'b'} || $broadcastAddress;
  $logFilespec = $opts{'l'} || $logFilespec;
+
  $timeout = $opts{'t'} || $timeout;
}
+
  $logFilespec = $opts{'l'} || $logFilespec;
+
}
################################################################################
+
 
# Subroutines
+
################################################################################
#
+
# Subroutines
+
#
#-------------------------------------------------------------------------------
+
 
# send UDP frame
+
#-------------------------------------------------------------------------------
#
+
# send UDP frame
sub sendUDP {
+
#
  my ($broadcastAddress, $portId, $command) = @_;
+
sub sendUDP {
  my $reply = '';
+
  my ($broadcastAddress, $portId, $command) = @_;
                                                                # open UDP socket
+
  my $reply = '';
  my $socket = IO::Socket::INET->new( Proto => 'udp', Broadcast => 1)
+
                                                              # open UDP socket
    or return('Socket open failed.');
+
  my $socket = IO::Socket::INET->new( Proto => 'udp', Broadcast => 1)
  my $ipAddress = inet_aton($broadcastAddress);
+
    or return('Socket open failed.');
  my $portAddress = sockaddr_in($portId, $ipAddress);
+
  my $ipAddress = inet_aton($broadcastAddress);
                                                                  # send command
+
  my $portAddress = sockaddr_in($portId, $ipAddress);
  send($socket, $command, 0, $portAddress);
+
                                                                  # send command
                                                                  # close socket
+
  send($socket, $command, 0, $portAddress);
  close($socket);
+
                                                                  # close socket
+
  close($socket);
  return($reply);
+
 
}
+
  return($reply);
+
}
################################################################################
+
 
# Main program
+
################################################################################
#
+
# Main program
                                                                    # log command
+
#
my $text = "In $room $kind, setting $object to \"$value\".";
+
                                                                  # log command
open(my $LOG_FILE, '>', $logFilespec) or die "Could not open file '$logFilespec' $!";
+
my $text = "In $room $kind, setting $object to \"$value\".";
print $LOG_FILE "$text\n";
+
open(my $LOG_FILE, '>', $logFilespec) or die "Could not open file '$logFilespec' $!";
close $LOG_FILE;
+
print $LOG_FILE "$text\n";
chmod(oct('0666'), $logFilespec);
+
close $LOG_FILE;
                                                        # display xPL frame info
+
chmod(oct('0666'), $logFilespec);
if ($verbose > 0) {
+
                                                        # display xPL frame info
  $text .= "\n";
+
if ($verbose > 0) {
  $text .= "${indent}broadcast address is \"$broadcastAddress\"\n";
+
  $text .= "\n";
  $text .= "${indent}message type is \"$messageType\"\n";
+
  $text .= "${indent}broadcast address is \"$broadcastAddress\"\n";
  $text .= "${indent}source is \"$source\"\n";
+
  $text .= "${indent}message type is \"$messageType\"\n";
  $text .= "${indent}target is \"$target\"\n";
+
  $text .= "${indent}source is \"$source\"\n";
  $text .= "${indent}scheme is \"$scheme\"\n";
+
  $text .= "${indent}target is \"$target\"\n";
  if ($ENV{'REQUEST_METHOD'}) {
+
  $text .= "${indent}scheme is \"$scheme\"\n";
    $text =~ s/\n$indent/\<br \/\>&nbsp;&nbsp;/g;
+
  if ($ENV{'REQUEST_METHOD'}) {
    print $cgi->header;
+
    $text =~ s/\n$indent/\<br \/\>&nbsp;&nbsp;/g;
    print $cgi->start_html;
+
    print $cgi->header;
    print("$text\n");
+
    print $cgi->start_html;
    print $cgi->end_html;
+
    print("$text\n");
  }
+
    print $cgi->end_html;
  else {
+
  }
    print("$separator\n");
+
  else {
    print("$text\n");
+
    print("$separator\n");
  }
+
    print("$text\n");
}
+
  }
                                                                # send xPL frame
+
}
my $message = "$messageType\n";
+
                                                                # send xPL frame
$message  .= "{\n";
+
my $message = "$messageType\n";
$message  .= "hop=1\n";
+
$message  .= "{\n";
$message  .= "source=$source\n";
+
$message  .= "hop=1\n";
$message  .= "target=$target\n";
+
$message  .= "source=$source\n";
$message  .= "}\n";
+
$message  .= "target=$target\n";
$message  .= "$scheme\n";
+
$message  .= "}\n";
$message  .= "{\n";
+
$message  .= "$scheme\n";
$message  .= "room=$room\n";
+
$message  .= "{\n";
$message  .= "kind=$kind\n";
+
$message  .= "room=$room\n";
$message  .= "object=$object\n";
+
$message  .= "kind=$kind\n";
$message  .= "value=$value\n";
+
$message  .= "object=$object\n";
$message  .= "command=set\n";
+
$message  .= "value=$value\n";
$message  .= "}\n";
+
$message  .= "command=set\n";
sendUDP($broadcastAddress, $portId, $message);
+
$message  .= "}\n";
 +
sendUDP($broadcastAddress, $portId, $message);
 +
</pre>
  
 
The idea of working both in terminal and in [https://en.wikipedia.org/wiki/Common_Gateway_Interface CGI] mode came from John Bent's [http://johnb.xplproject.org.uk/info/perl/ xPL ToolKit for Perl].
 
The idea of working both in terminal and in [https://en.wikipedia.org/wiki/Common_Gateway_Interface CGI] mode came from John Bent's [http://johnb.xplproject.org.uk/info/perl/ xPL ToolKit for Perl].
Line 176: Line 185:
  
 
Test it in a terminal window:
 
Test it in a terminal window:
  cd WWW_ROOT/homeControl/
+
  cd WWW_CONTROL/
 
  ./sendState.cgi -v study lights ceiling on
 
  ./sendState.cgi -v study lights ceiling on
 
The terminal should display information about what is being sent,
 
The terminal should display information about what is being sent,
Line 188: Line 197:
 
and the home state device shoiud turn the light off.
 
and the home state device shoiud turn the light off.
  
= Prepare a home control page =
+
= Home control page =
  
Create the home control directory:
+
In the www home control directory, create a <code>simple.html</code> control page:
WWW_CONTROL=$WWW_ROOT/homeControl
+
mkdir -p $WWW_CONTROL
+
chmod -R 775 $WWW_CONTROL
+
chown -R control:users $WWW_CONTROL
+
cd $WWW_CONTROL
+
 
+
In this directory, create a <code>simple.html</code> control page:
+
 
<pre>
 
<pre>
 
<html>
 
<html>
 
   <head>
 
   <head>
     <script src="//code.jquery.com/jquery-1.11.0.min.js">
+
    <!--
     </script>
+
     <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
 +
     -->
 +
    <script src="jquery-2.1.4.min.js"></script>
 
   </head>
 
   </head>
 
   <body>
 
   <body>
Line 218: Line 222:
 
     </table>
 
     </table>
  
     <!-- Websocket java script ............................................. -->
+
     <!-- Websocket javascript .............................................. -->
 
     <script>
 
     <script>
 
       $().ready(function() {
 
       $().ready(function() {
         var ws = new WebSocket('ws://harmonia.local:8080/');
+
         var room = 'study';
 
+
         var kind = 'lights';
         ws.onopen = function() {
+
        var object = '';
          console.log("Web socket started");
+
         var value = '';
         }
+
 
                                                             // outgoing messages
 
                                                             // outgoing messages
 
         $('#ceiling').on('change', function() {
 
         $('#ceiling').on('change', function() {
           ws.send('ceiling ' + $(this).is(':checked'));
+
           object = 'ceiling';
 +
          value = ($(this).is(':checked') == true ? 'on' : 'off');
 +
          $.post('sendState.cgi', {room: room, kind: kind, object: object, value: value})
 +
          console.log('sending ' + room + ' ' + kind + ' ' + object + ' "' + value + '"');
 
         });
 
         });
 
         $('#stand').on('change', function() {
 
         $('#stand').on('change', function() {
           ws.send('stand ' + $(this).is(':checked'));
+
           object = 'stand';
 +
          value = ($(this).is(':checked') == true ? 'on' : 'off');
 +
          $.post('sendState.cgi', {room: room, kind: 'lights', object: object, value: value})
 +
          console.log('sending ' + room + ' ' + kind + ' ' + object + ' "' + value + '"');
 
         });
 
         });
                                                              // polling message
 
        window.setInterval(
 
          function() {
 
            ws.send('poll request');
 
          }
 
          , 100
 
        );
 
                                                            // incoming messages
 
        ws.onmessage = function(message) {
 
          console.log(message.data);
 
          var words = message.data.split(' ');
 
 
          if (words[0] === 'ceiling') {
 
              $('#ceiling').prop('checked', words[1] == 'true');
 
          }
 
          if (words[0] === 'stand') {
 
              $('#stand').prop('checked', words[1] == 'true');
 
          }
 
        }
 
 
       });
 
       });
 
     </script>
 
     </script>
Line 260: Line 250:
 
Navigate to the control page: <code>http://harmonia.local/homeControl/simple.html</code>
 
Navigate to the control page: <code>http://harmonia.local/homeControl/simple.html</code>
  
= Implement a WebSocket server =
+
The web browser should show two buttons.
 +
Clicking on them should launch the CGI script and turn the lights on or off.
  
 
[[Category: all]] [[Category: install]] [[Category: web]]
 
[[Category: all]] [[Category: install]] [[Category: web]]

Revision as of 15:08, 24 June 2015

Controlling the home from distance is made via a web access.

In this example, the server is harmonia.local: evidently, this has to be replaced by your local server name.

Install a web server

Install the web server:

su
apt-get update
apt-get install lighttpd
apt-get install php5-cgi
lighttpd-enable-mod fastcgi fastcgi-php
lighty-enable-mod cgi
service lighttpd reload
service lighttpd status

Configure the base directory and modify the line with server.document-root:

WWW_ROOT=/mnt/storage/www/
nano /etc/lighttpd/lighttpd.conf
service lighttpd reload
cp /var/www/index.lighttpd.html $WWW_ROOT

Edit /etc/lighttpd/conf-enabled/10-cgi.conf to allow CGI scripts execution:

# /usr/share/doc/lighttpd/cgi.txt
server.modules += ( "mod_cgi" )
$HTTP["url"] =~ "^/homeControl/" {
  cgi.assign = ( ".cgi" => "/usr/bin/perl" )
}

Navigate to your server within a web browser. You should discover the default lighttpd placeholder page.

Install jQuery

Download the latest compressed, production jQuery version.

wget http://code.jquery.com/jquery-2.1.4.min.js

CGI control script

Create the home control directory:

WWW_CONTROL=$WWW_ROOT/homeControl
mkdir -p $WWW_CONTROL
chmod -R 775 $WWW_CONTROL
chown -R control:users $WWW_CONTROL
cd $WWW_CONTROL

The following script can be run either from a terminal or as a Common Gateway Interface (CGI) script:

#!/usr/bin/perl
use IO::Socket;
use CGI;
my $cgi = CGI->new;

#-------------------------------------------------------------------------------
# constants
#
my $portId = 3865;
my $messageType = 'xpl-cmnd';
my $source = 'sendstate.harmonia';
my $target = 'dspc-state.home';
my $scheme = 'state.basic';

$separator = '-' x 80;
$indent = ' ' x 2;

#-------------------------------------------------------------------------------
# Input arguments
#
my $verbose = 1;
my ($room, $kind, $object, $value);
my $broadcastAddress = '255.255.255.255';
my $timeout = -1;
my $logFilespec = '/tmp/sendState.log';

if ($ENV{'REQUEST_METHOD'}) {
                                                       # get parameters from URL
  $room   = $cgi->param('room');    
  $kind   = $cgi->param('kind');    
  $object = $cgi->param('object');    
  $value  = $cgi->param('value');    
}
else {
                                              # get parameters from command line
  use Getopt::Std;
  my %opts;
  getopts('hvb:t:l:', \%opts);
  
  die("\n".
      "Usage: $0 [-hv] [-b address] [-t timeout] room kind object value\n".
      "\n".
      "Parameters:\n".
      "${indent}-h      display this help message\n".
      "${indent}-v      verbose\n".
      "${indent}-b addr broadcast address\n".
      "${indent}-t time timeout\n".
      "${indent}-l file log filespec\n".
      "\n".
      "The message is sent to machine <server>, UDP port <portId>.\n".
      "\n".
      "More information with: perldoc $0\n".
      "\n".
      ""
     ) if ($opts{h});
  $verbose = $opts{v};

  ($room, $kind, $object, $value) = @ARGV;
  $broadcastAddress = $opts{'b'} || $broadcastAddress;
  $timeout = $opts{'t'} || $timeout;
  $logFilespec = $opts{'l'} || $logFilespec;
}

################################################################################
# Subroutines
#

#-------------------------------------------------------------------------------
# send UDP frame
#
sub sendUDP {
  my ($broadcastAddress, $portId, $command) = @_;
  my $reply = '';
                                                               # open UDP socket
  my $socket = IO::Socket::INET->new( Proto => 'udp', Broadcast => 1)
    or return('Socket open failed.');
  my $ipAddress = inet_aton($broadcastAddress);
  my $portAddress = sockaddr_in($portId, $ipAddress);
                                                                  # send command
  send($socket, $command, 0, $portAddress);
                                                                  # close socket
  close($socket);

  return($reply);
}

################################################################################
# Main program
#
                                                                   # log command
my $text = "In $room $kind, setting $object to \"$value\".";
open(my $LOG_FILE, '>', $logFilespec) or die "Could not open file '$logFilespec' $!";
print $LOG_FILE "$text\n";
close $LOG_FILE;
chmod(oct('0666'), $logFilespec);
                                                        # display xPL frame info
if ($verbose > 0) {
  $text .= "\n";
  $text .= "${indent}broadcast address is \"$broadcastAddress\"\n";
  $text .= "${indent}message type is \"$messageType\"\n";
  $text .= "${indent}source is \"$source\"\n";
  $text .= "${indent}target is \"$target\"\n";
  $text .= "${indent}scheme is \"$scheme\"\n";
  if ($ENV{'REQUEST_METHOD'}) {
    $text =~ s/\n$indent/\<br \/\>  /g;
    print $cgi->header;
    print $cgi->start_html;
    print("$text\n");
    print $cgi->end_html;
  }
  else {
    print("$separator\n");
    print("$text\n");
  }
}
                                                                # send xPL frame
my $message = "$messageType\n";
$message   .= "{\n";
$message   .= "hop=1\n";
$message   .= "source=$source\n";
$message   .= "target=$target\n";
$message   .= "}\n";
$message   .= "$scheme\n";
$message   .= "{\n";
$message   .= "room=$room\n";
$message   .= "kind=$kind\n";
$message   .= "object=$object\n";
$message   .= "value=$value\n";
$message   .= "command=set\n";
$message   .= "}\n";
sendUDP($broadcastAddress, $portId, $message);

The idea of working both in terminal and in CGI mode came from John Bent's xPL ToolKit for Perl.

Save the script as /homeControl/sendState.cgi in the web pages directory.

Test it in a terminal window:

cd WWW_CONTROL/
./sendState.cgi -v study lights ceiling on

The terminal should display information about what is being sent, an xPL monitor should show the corresponding frame and the home state xPL device should turn the corresponding light on.

Test it as a CGI by navigating to the control page:

http://harmonia.local/homeControl/sendState.cgi?room=study&kind=lights&object=ceiling&value=off

The browser shoud display the same info as the terminal, the monitor should show the frame and the home state device shoiud turn the light off.

Home control page

In the www home control directory, create a simple.html control page:

<html>
  <head>
    <!--
    <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
    -->
    <script src="jquery-2.1.4.min.js"></script>
  </head>
  <body>
    <!-- Light controls .................................................... -->
    <br />
    <table align="center" border='0px' cellpadding='12px' cellspacing='0px' bgcolor="#CCCCCC">
      <tr>
        <th width="240px">ceiling</th>
        <th width="240px">stand</th>
      </tr>
      <tr>
        <td align="center"><input id="ceiling" type="checkbox" /></td>
        <td align="center"><input id="stand" type="checkbox" /></td>
      </tr>
    </table>

    <!-- Websocket javascript .............................................. -->
    <script>
      $().ready(function() {
        var room = 'study';
        var kind = 'lights';
        var object = '';
        var value = '';
                                                            // outgoing messages
        $('#ceiling').on('change', function() {
          object = 'ceiling';
          value = ($(this).is(':checked') == true ? 'on' : 'off');
          $.post('sendState.cgi', {room: room, kind: kind, object: object, value: value})
          console.log('sending ' + room + ' ' + kind + ' ' + object + ' "' + value + '"');
        });
        $('#stand').on('change', function() {
          object = 'stand';
          value = ($(this).is(':checked') == true ? 'on' : 'off');
          $.post('sendState.cgi', {room: room, kind: 'lights', object: object, value: value})
          console.log('sending ' + room + ' ' + kind + ' ' + object + ' "' + value + '"');
        });
      });
    </script>

  </body>
</html>

Navigate to the control page: http://harmonia.local/homeControl/simple.html

The web browser should show two buttons. Clicking on them should launch the CGI script and turn the lights on or off.