Home | Programming Resources | Home Automation |     Share This Page
Home Automation
All Content Copyright © 2008, P. LutusMessage Page

Click here for a plain-text copy of the PHP script.
Web Page Generator PHP Script Listing
<?php

/***************************************************************************
 *   Copyright (C) 2008, Paul Lutus                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

/*
 *
 * Required: ISY-26 software version 2.6.2 or newer.
 *
 * Version 3.3, 10/03/2008: Modified one line to accommodate changes in firmware >= 2.6.7
 *
 * Version 3.2, 03/02/2008: Added a filter for control and scene names beginning
 * with a double-underscore, (like __name) to exclude them from the display.
 *
 * Version 3.1, 03/02/2008: At the suggestion of a reader who has dimmers, changed
 * regex to accommodate intermediate "percent" states between on and off,
 * translating them all into "On".
 *
 */

// BEGIN user definitions

// Show controls table

$show_controls = true;

// Show scenes table

$show_scenes = true;

// ISY-26 access name or IP

$isy26_address = "pl-isy26";

// ISY-26 logon name

$logon_name="admin";

// ISY-26 access password

$password="(your password)";

// Specify a convenient font size

$font_size = "12pt";

// Specify how many cells in table rows

$control_row_length = 4;
$scene_row_length = 4;

// Specify seconds between page refreshes

$refresh_interval = 5;

// END user definitions

$controls_path = "/devices";
$scenes_path = "/scenes";
$change_path = "/change";

function wrap_tag($tag,$content,$extension = "") {
  return "<$tag $extension>$content</$tag>";
}

function fetch_http($host,$port,$method,$path,$args = null)
{
  global $logon_name,$password;
  $buf = "";
  $auth = base64_encode("$logon_name:$password");
  try {
    $fp = fsockopen($host, $port);
    if ($args && $method == 'GET') {
      $path .= '?' . $args;
    }
    $content = "$method $path HTTP/1.1\r\n";
    $content .= "Host: $host\r\n";
    $content .= "Authorization: Basic $auth\r\n";
    $content .= "Content-type: application/x-www-form-urlencoded\r\n";
    $content .= "Content-length: " . strlen($args) . "\r\n";
    $content .= "Connection: close\r\n\r\n";
    if ($args && $method == 'POST') {
      $content .= $args;
    }
    fputs($fp, $content);
    while (!feof($fp)) {
      $buf .= fgets($fp,1024);
    }
    fclose($fp);
  }
  catch(Exception $e) {
    echo 'Error: ',  $e->getMessage(), "<br/>\n";
  }
  return $buf;
}

// fetch ISY-26 data page

function fetch_table_data($path) {
  
  global $isy26_address;
  global $control_row_length,$scene_row_length,$controls_path;
  
  $result = "";
  
  // Fetch a page using GET method
  
  $data = fetch_http($isy26_address,80,"GET",$path);
  
  // Did the page load fail (sometimes happens)?
  
  if(!preg_match("%</table>%ism",$data)) {
    $result = $data;
  }
  else {
    
    // isolate the data table
    $data = preg_replace("%^.*<table.*?>(.*)</table>.*%is","$1",$data);
    // make an array of row contents
    $n = preg_match_all("%<tr>(.*?)</tr>%is",$data,$matches,PREG_PATTERN_ORDER);
    $row_array = $matches[1];
    // drop header row
    array_shift($row_array);
    if($path == $controls_path) {
      $row_length = $control_row_length;
      // create an array of device data: name,address,state (on/off)
      $device_array = preg_replace("%.*?node=(.*?)\">(.*?)</a></td>.*?(\d+ percent|On|Off).*$%","$2,$1,$3",$row_array);
    }
    else {
      $row_length = $scene_row_length;
      // create an array of scene data: name,address,-
      $device_array = preg_replace("%.*?node=(.*?)\">(.*?)</a></td>.*$%","$2,$1,-",$row_array);
    }
    
    // sort controls and scenes by name
    sort($device_array);
    
    // build the display Web page
    $pa = array();
    $n = 0;
    $row = "";
    foreach ($device_array as $record) {
      list($name,$address,$action) = split(",",$record);
      // To exclude a control or scene from the display,
      // prefix its name with a double-underscore
      if(!preg_match("/^__/",$name)) {
        $n++;
        // all percentage values count as "On"
        $on_state = ($action != "Off" && $action != "-");
        $class = ($on_state && !preg_match("/All/",$name))?"spy":"spn";
        $next_state = $on_state?"Off":"On";
        if($path == $controls_path) {
          $arg = $address . "," . $next_state . ",d";
          $title = "Turn " . $next_state . " control '" . $name . "'";
          $span = wrap_tag("span",$name,"class=\"$class\" title=\"$title\" onClick=\"clicked('$arg');\"");
          $row .= wrap_tag("td",$span);
        }
        else {
          $arg = $address . ",On,s";
          $title = "Turn On scene '" . $name . "'";
          $span = wrap_tag("span",$name . " On","class=\"$class\" title=\"$title\" onClick=\"clicked('$arg');\"");
          $row .= wrap_tag("td",$span);
          $arg = $address . ",Off,s";
          $title = "Turn Off scene '" . $name . "'";
          $span = wrap_tag("span",$name . " Off","class=\"$class\" title=\"$title\" onClick=\"clicked('$arg');\"");
          $row .= wrap_tag("td",$span);
          $n++;
        }
      }
      // Test for row length
      if(!($n % $row_length)) {
        $pa[] = wrap_tag("tr",$row);
        $row = "";
      }
    }
    // Add possible incomplete row
    if(strlen($row) > 0) {
      while($n % $row_length) {
        $row .= wrap_tag("td","&nbsp;");
        $len = strlen($row);
        $n++;
      }
      $pa[] = wrap_tag("tr",$row);
    }
    $result = join("\n",$pa);
    $result = wrap_tag("table", "\n" . $result . "\n","class=\"bordered\" cellpadding=\"0\" cellspacing=\"0\"");
    $title = ($path == $controls_path)?"Controls":"Scenes";
    $title = wrap_tag("b",$title . ":");
    $title = wrap_tag("p",$title);
    $result = $title . $result;
  }
  return $result;
}
// if there is POST data from a prior control input, then submit it to the ISY-26.
// The POST info has this form: node (address), action:On or Off, type: [d]evice or [s]cene

if(array_key_exists('info',$_POST)) {
  list($node,$action,$type) = split(",",$_POST['info']);
  $out = "node=$node&submit=$action";
  $result = fetch_http($isy26_address,80,"POST",$change_path,$out);
  // If this was a scene command, delay for ISY-26 to update its state
  if($type == "s") {
    usleep(250000);
  }
}
$page = "";
if($show_scenes) {
  $page .= fetch_table_data($scenes_path);
}
if($show_controls) {
  $page .= fetch_table_data($controls_path);
}
?>
<html>
<head>
<title>Lighting Controls</title>
<script type="text/javascript" language="JavaScript">

function clicked(s) {
  document.form1.info.value = s;
  document.form1.submit();
}

</script>
<style type="text/css">

body {
  background-color:#e0f0ff;
}

table.bordered,table.bordered td {
  border-collapse: collapse;
  border: 1px solid #000000;
}

* {
  font-size:<?php echo $font_size; ?>;
}

span:hover {
  color:black;
  text-decoration:underline;
}

.spy,.spn {
  color:#808080;
  padding:2px;
  display:block;
  text-align:center;
  cursor:hand;
  cursor:pointer;
}

/* color for "On" */
.spy {
  background:#ffff80;
}

/* color for "Off" */
.spn {
  background:#ffffff;
}

</style>
<meta http-equiv="refresh" content="<?php echo $refresh_interval; ?>"/>
</head>
<body>
<div align="center"><?php echo $page; ?></div>
<form name="form1" method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<input type="hidden" name="info" value=""/>
</form>
</body>
</html>
 

Home | Programming Resources | Home Automation |     Share This Page