Tutorial for the Web-IO Digital:
Controlling a Web-IO Digital from your own web page using PHP
The Web-IO Digital 4.0 models can be controlled using HTTP requests. Use of HTTP requests for data exchange is supported by most script and high level languages. PHP is available as a script language on nearly any web server and is perfect for handling communication with the Web-IO.
The example shown here works in two parts. It separates the dynamic display of the IO states using HTMP, JavaScript and AJAX (web page) and communication with the Web-IO using PHP (-script).
The centerpiece is the PHP script webiohttprequest.php, which needs no display elements and simply handles data exchange. The web page on which the IO states are displayed is calls the PHP script using AJAX and requests the status of the Web-IO.
One advantage of this technique is that the same PHP script can be used to access multiple Web-IOs, whereby parameters that are included determine the destination Web-IO. If the Web-IOs and the PHP server are located behind a firewall, only access to the PHP server to the outside needs to be enabled.
The following example shows how the PHP script is constructed and how it is controlled with a simple web page and the necessary functions. The display is prepared for the Web-IO Digital 4.0 2xIn, 2xOut.
Preparations
- Provide power to the Web-IO and connect the IOs
- Connect the Web-IO to the network
- Assign IP addresses
On the Web-IO in Communication channels >> Web-API activate Allow HTTP-Request and enable outputs for switching
The PHP script
The PHP script webiohttprequest.php must have various parameters transmitted to it when called. These parameters are passed as part of the HTTP request.
- HTTPS
HTTPS=0 - the request is sent as an HTTP request
HTTPS=1 - the request is sent encrypted as an HTTPS request - IP
IP=<IP address of the Web-IO> - PORT
PORT=<HTTP(s) port of the Web-IO> - PW
PW=<Password of the Web-IO> - COMMAND
COMMAND=<The command to be sent to the Web-IO>
possible commands: input, output, counter, outputaccess, single - STATE (only for command outputaccess)
STATE=<Bit pattern of the switching states to which the outputs should be switched in Hexadecimal> - MASK (only for command outputaccess
MASK=<Bit pattern of the outputs to be switched should be in Hexadecimal>
The commands and parameters to be sent under COMMAND correspond to the basic commands of the HTTP requests.
To send HTTP requests the PHP script uses the PHP function library CURL.
<?php
$PROTO="http://";
$PORT="80";
if (!isset($_GET[’COMMAND’])) {die( ’ERROR command’ );} else {$COMMAND=$_GET[’COMMAND’];}
if (!isset($_GET[’IP’])) {die( ’ERROR ip’ );} else {$IP=$_GET[’IP’];}
if (!isset($_GET[’HTTPS’])) {$PROTO=’http://’;}
else
{ if ($_GET[’HTTPS’] == 1)
{ $PROTO=’https://’;
$PORT=’443’;
}
}
if (isset($_GET[’PORT’])) {$PORT=$_GET[’PORT’];}
if (!isset($_GET[’PW’])) {$PW="";} else {$PW=$_GET[’PW’];}
if (!isset($_GET[’MASK’])) {$MASK="0FFF";} else {$MASK=$_GET[’MASK’];}
if (!isset($_GET[’STATE’]))
{ $STATE="0000";
$MASK="0000";
}
else $STATE=$_GET[’STATE’];
{ if ($COMMAND == "outputaccess")
{ $URL=$PROTO.$IP.":".$PORT."/".$COMMAND."?PW=".$PW."&Mask=".$MASK."&State=".$STATE."&";
}
else
{ if (substr($COMMAND,0,6) == "single")
{ $URL=$PROTO.$IP.":".$PORT."/".$COMMAND;
}
else
{ $URL=$PROTO.$IP.":".$PORT."/".$COMMAND."?PW=".$PW."&";
}
}
$ch = curl_init();
$options = array(
CURLOPT_URL => $URL,
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don’t return headers
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_USERAGENT => "webio", // who am i
CURLOPT_CONNECTTIMEOUT => 20, // timeout on connect
CURLOPT_TIMEOUT => 20, // timeout on response
CURLOPT_MAXREDIRS => 1, // stop after 10 redirects
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false,
);
curl_setopt_array( $ch, $options );
$data = curl_exec($ch);
if ($data==false)
{ die(’ERROR ’.$URL);
}
else
{ $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_status==200)
{ echo $data;
}
else
{ die(’ERROR ’.$URL.’ status ’.$http_status);
}
}
curl_close($ch);
}
?>
Basic structure of the web page
The HTML basic structure of this page looks as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1250">
<title>Web-IO Digital, Cross Origin</title>
<style type="text/css">
* { font-family:arial; }
table { font-size:14px; text-align:center; padding-left:5px; padding-right:5px;}
.borderLeft { border-left:1px solid #000000; }
.button { font-size:9px; width:40px; }
.name { font-size:20px; font-weight:bold; text-align:center }
.table { background-color:#d6e8ff; border-collapse:collapse; border:1px solid #000000; }
.whiteBack { background-color:#ffffff; }
</style>
<script language="JavaScript" type="text/javascript">
........
........
</script>
</head>
<body onload="CommandLoop()">
<form>
<div align="center">
<h2>Web-IO 0</h2>
<span>Password: </span>
<input id="webio0pw" type="password" maxlength="31" size="20"">
</div>
</form>
<table align="center" class="table">
<tr>
<td>input 0</td>
<td id="webio0input0">OFF</td>
<td id="webio0counter0">0</td>
<td>
<input class="button" onclick="clearCounter(0,0);" type="button" value="Clear">
</td>
<td class="borderLeft">output 0</td>
<td id="webio0output0">OFF</td>
<td>
<input class="button" onclick="setOutput(0,0,1);" type="button" value="ON">
<input class="button" onclick="setOutput(0,0,0);" type="button" value="OFF">
</td>
</tr>
<tr class="whiteBack">
<td>input 1</td>
<td id="webio0input1">OFF</td>
<td id="webio0counter1">0</td>
<td>
<input class="button" onclick="clearCounter(0,1);" type="button" value="Clear">
</td>
<td class="borderLeft">output 1</td>
<td id="webio0output1">OFF</td>
<td>
<input class="button" onclick="setOutput(0,1,1);" type="button" value="ON">
<input class="button" onclick="setOutput(0,1,0);" type="button" value="OFF">
</td>
</tr>
</table>
<br />
<form>
<div align="center">
<h2>Web-IO 1</h2>
<span>Password: </span>
<input id="webio1pw" type="password" maxlength="31" size="20"">
</div>
</form>
<table align="center" class="table">
<tr>
<td>input 0</td>
<td id="webio1input0">OFF</td>
<td id="webio1counter0">0</td>
<td>
<input class="button" onclick="clearCounter(1,0);" type="button" value="Clear">
</td>
<td class="borderLeft">output 0</td>
<td id="webio1output0">OFF</td>
<td>
<input class="button" onclick="setOutput(1,0,1);" type="button" value="ON">
<input class="button" onclick="setOutput(1,0,0);" type="button" value="OFF">
</td>
</tr>
<tr class="whiteBack">
<td>input 1</td>
<td id="webio1input1">OFF</td>
<td id="webio1counter1">0</td>
<td>
<input class="button" onclick="clearCounter(1,1);" type="button" value="Clear">
</td>
<td class="borderLeft">output 1</td>
<td id="webio1output1">OFF</td>
<td>
<input class="button" onclick="setOutput(1,1,1);" type="button" value="ON">
<input class="button" onclick="setOutput(1,1,0);" type="button" value="OFF">
</td>
</tr>
</table>
</body>
</html>
The head area and style information will not be covered here. The contents of the script area are described in the following. Important in the body area are the id nomenclatures by means of which the objects and table cells are accessed in the JavaScript functions. Using onclick the function assigned to the buttons is determined. As a parameter the number of the Web-IO followed by the number of counters and outputs is transmitted. For the outputs the second parameter indicates the status (0=OFF, 1=ON).
By maintaining this system the example can be adapted to other Web-IO models without changing the JavaScript functions simply by adding additional table lines.
Global variables and functions in JavaScript
First a few global variables need to be declared.
var MaxI = 2;
var MaxO = 2;
var WebioIP = [’192.168.0.25’, ’192.168.0.26’];
var WebioPort = [’80’, ’80’];
var ApplicationStep = 0;
var Interval = 250;
// Converting hexadecimal string to Integer
function HexToInt(HexStr)
{ var TempVal;
var HexVal=0;
for( var i=0; i<HexStr.length;i++)
{ if (HexStr.charCodeAt(i) > 57)
{ TempVal = HexStr.charCodeAt(i) - 55;
}
else
{ TempVal = HexStr.charCodeAt(i) - 48;
}
HexVal=HexVal+TempVal*Math.pow(16, HexStr.length-i-1);
}
return HexVal;
}
Sending HTTP requests and receiving HTTP replies
// Sending command lines to Web-IO and receiving IO State
function DataRequest(WebioNo, SendString)
{ var xmlHttp;
if( window.ActiveXObject ) // Internet Explorer
{ xmlHttp = new ActiveXObject( "Microsoft.XMLHTTP" );
}
else if(window.XMLHttpRequest ) // Mozilla, Opera und Safari
{ xmlHttp = new XMLHttpRequest();
}
if (xmlHttp)
{ xmlHttp.onreadystatechange = function()
{ if (xmlHttp.readyState == 4)
{ if (xmlHttp.status == 200)
{ if (xmlHttp.responseText.length > 0)
{ updateDisplay(WebioNo, xmlHttp.responseText);
}
xmlHttp=null;
}
}
}
xmlHttp.open("GET", SendString, true);
xmlHttp.setRequestHeader("If-Modified-Since", "Thu, 1 Jan 1970 00:00:00 GMT");
xmlHttp.send(null);
}
}
Processing of HTTP Request and HTTP Reply is handled by the function DataRequest
. Unfortunately Internet Explorer uses different mechanisms for processing HTTP requests than other browsers. Therefore the function first checks in which browser the web page is being opened in. The HTTP Request sent as SendString
is then sent to the server or Web-IO from which the web page was loaded. The HTTP reply is then sent to the function UpdateDisplay
.
Cyclical querying of inputs, outputs and counters
// Preparing command lines for cycle sending
function CommandLoop()
{ var Command =’’;
var CommandString =’’;
var WebioNo = 0;
ApplicationStep++;
switch(ApplicationStep)
{ case 1:
Command = ’input’;
break;
case 2:
Command = ’input’;
WebioNo = 1;
break;
case 3:
Command = ’output’;
break;
case 4:
Command = ’output’;
WebioNo = 1;
break;
case 5:
Command = ’counter’;
break;
case 6:
Command = ’counter’;
WebioNo = 1;
ApplicationStep = 0;
break;
}
var IOPassword = document.getElementById(’webio’+WebioNo+’pw’).value;
CommandString = ’webiohttprequest.php?IP=’+WebioIP[WebioNo]+’&PORT=’+WebioPort[WebioNo]+’&COMMAND=’+Command+’&PW=’+ IOPassword;
if (WebioPort[WebioNo] == ’443’)
{ CommandString = CommandSting + ’&HTTPS=1’
}
DataRequest(WebioNo, CommandString);
maintimer = setTimeout("CommandLoop()", Interval);
}
The CommandLoop
function is started using the parameter onload in the body tag as soon as the web page is fully loaded. The function uses the DataRequest
function to alternatingly send the HTTP Requests to the Web-IOs for querying inputs, outputs and counters and calls itself again after a time delay. In this way the IO states are continually refreshed at a fixed interval.
Switching outputs
// Set Output to ON (requested from User)
function setOutput(WebioNo, OutNo, OutVal)
{ var IOPassword = document.getElementById(’webio’+WebioNo+’pw’).value;
var CommandString = ’webiohttprequest.php?IP=’+WebioIP[WebioNo]+’&PORT=’+WebioPort[WebioNo]+’&COMMAND=outputaccess&PW=’+ IOPassword+’&MASK=’+(2**OutNo).toString(16);
if(OutVal>0)
{ CommandString = CommandString + ’&STATE=0fff’;
}
else
{ CommandString = CommandString + ’&STATE=0’;
}
if (WebioPort[WebioNo] == ’443’)
{ CommandString = CommandSting + ’&HTTPS=1’
}
DataRequest(WebioNo, CommandString);
}
Clicking on the corresponding buttons invokes the setOutput
function and sends the number of the Web-IO, of the output and the states to be switched. The DataRequest
function sends the necessary HTTP request to the Web-IO.
Clearing the counters
// Set Counter to 0 (requested from display)
function clearCounter(WebioNo, CounterNo)
{ var IOPassword = document.getElementById(’webio’+WebioNo+’pw’).value;
var CommandString = ’webiohttprequest.php?IP=’+WebioIP[WebioNo]+’&PORT=’+WebioPort[WebioNo]+’&COMMAND=counterclear’+CounterNo+’&PW=’+ IOPassword;
if (WebioPort[WebioNo] == ’443’)
{ CommandString = CommandSting + ’&HTTPS=1’
}
DataRequest(WebioNo, CommandString);
}
Clicking on the corresponding buttons calls the clearCounter
function and sends the number of the Web-IO and the input number.
Refreshing the web page contents
// Dynamic update of the display depending on IO state
function updateDisplay(WebioNo, ReceiveStr)
{ var HexVal;
var state;
var ReceiveData = ReceiveStr.split(’;’)
// Display Intput state
if (ReceiveData[ReceiveData.length - 2].substring(0, 1) == ’i’)
{ HexVal = HexToInt(ReceiveData[ReceiveData.length - 1]);
for (var i = 0; i < MaxI; i++)
{ state = false;
if ((HexVal & Math.pow(2, i)) == Math.pow(2, i))
{ state = true;
}
document.getElementById(’webio’+WebioNo+’input’+i).firstChild.data = ( !state ) ? ’OFF’ : ’ON’;
}
}
// Display Output state
if (ReceiveData[ReceiveData.length - 2].substring(0, 1) == ’o’)
{ HexVal = HexToInt(ReceiveData[ReceiveData.length - 1]);
for (var i = 0; i < MaxO; i++)
{ state = false;
if ((HexVal & Math.pow(2, i)) == Math.pow(2, i))
{ state = true;
}
document.getElementById(’webio’+WebioNo+’output’+i).firstChild.data = ( !state ) ? ’OFF’ : ’ON’;
}
}
//Display Counter
if (ReceiveData.length - MaxI - 1 >= 0)
{ if (ReceiveData[ReceiveData.length - MaxI - 1].substring(0, 1) == ’c’)
{ for (var i = 0; i < MaxI; i++)
{ document.getElementById(’webio’+WebioNo+’counter’ + i).innerHTML = ReceiveData[ReceiveData.length - MaxI + i]
}
}
}
//Display cleared Counter
if (ReceiveData[ReceiveData.length - 2].substring(0, 1) == ’c’)
{ document.getElementById(’webio’+WebioNo+’counter’+ ReceiveData[ReceiveData.length - 2].substring(7, ReceiveData[ReceiveData.length - 2].length)).innerHTML = ReceiveData[ReceiveData.length - 1];
}
}
In reply to an HTTP request the Web-IO always sends the actual command and, separated by a semicolon, one or more parameters. The reply from the Web-IO passes the PHP script 1:1.
For an input query for example input;1
The function UpdateDisplay
uses split
to break down the passed string into a string array. For the input example the result is an array with the first field variable input
and the second 1
. The first letter of the first field variable determines whether the reply affects an input, output or the counters.
The second field variable contains for input and output the bit pattern for the switching state of the IOs (Bit0=Input0, Bit1=Input1, .....). Since the value is sent in hexadecimal format, it must first be converted using the function HexToInt
into a decimal number.
Using an AND operation on the input value with the power of 2, which corresponds to the bit value of the individual inputs and outputs, the determination is made whether the affected input (output) is 0 or 1, i.e. OFF or ON. This is done in a loop which runs depending on the number of IOs.
Using the JavaScript function document.getElementById
the display object to be refreshed is identified and adjusted correspondingly to the current switching state.
The same mechanisms are used for refreshing the counters, except that there is no hex to decimal conversion since the counter states are already passed in decimal format.
The example supports the most important functions of the Web-IO which are available using HTTP requests, optimized for the Web-IO Digital 4.0 2xIn, 2xOut. For the other Web-IO models you may have to make changes to the program. A detailed description of the binary structures can be found in the JavaScript section. A detailed description for using HTTP requests for the Web-IO Digital models can be found in the Request command overview or in the programming manual for the Web-IO.