= 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"; } 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(), "
\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("%%ism",$data)) { $result = $data; } else { // isolate the data table $data = preg_replace("%^.*(.*).*%is","$1",$data); // make an array of row contents $n = preg_match_all("%(.*?)%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=(.*?)\">(.*?).*?(\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=(.*?)\">(.*?).*$%","$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"," "); $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); } ?> Lighting Controls