Due to maintenance work, W&T will be closed on 19.04.2024!

You can reach our technical hotline at:
+49 202/2680-110 or under the emergency number: +49 179/4317651


On Monday 22.04.2024 we will be available as usual.

W&T conecta
Interfaces para TCP/IP, Ethernet, RS-232, RS-485, USB, 20mA, fibra óptica de vidrio y de plástico, http, SNMP, OPC, Modbus TCP, I/O digital, I/O analógico, ISA, PCI

Tutorial al Web-IO digital:

Control de Web-IO Digital desde una página web propia con PHP


Los modelos de Web-IO Digital 4.0 pueden ser activados mediante peticiones HTTP. La mayoría de lenguajes de alto nivel y de script permiten el uso de las peticiones HTTP para el intercambio de datos. PHP está disponible en casi cualquier servidor de web como lenguaje de script y es idóneo para desarrollar la comunicación con el Web-IO.

El ejemplo mostrado aquí trabaja en dos partes. Separa la presentación dinámica de los estados de las EA vía HTML, JavaScript o AJAX (página web) y la comunicación con el Web-IO vía (script) PHP.

La parte principal es el script de PHP webiohttprequest.php, que no necesita elementos de presentación y se encarga exclusivamente del intercambio de datos. Según la página web en la que se presenten los estados de las EA, activa mediante AJAX el script PHP y solicita el estado del Web-IO.

Una ventaja de esta técnica es que permite consultar a varios Web-IO con el mismo script de PHP. El parámetro adjunto determina el Web-IO destinatario. Si los Web-IO y el servidor de PHP están protegidos por un cortafuegos, solo es necesario habilitar hacia fuera el acceso al servidor de PHP.

Control de Web-IO con AJAX

El siguiente ejemplo muestra la estructura del script de PHP y cómo se activa con una página web sencilla y las funciones necesarias. La indicación está preparada para el Web-IO Digital 4.0 2xIn, 2xOut.


Preparativos


El script de PHP

Al script de PHP webiohttprequest.php hay que transmitirle diversos parámetros al activarlo. Esos parámetros están integrados en la petición HTTP.

  • HTTPS
    HTTPS=0 - se envía la petición como petición HTTP
    HTTPS=1 - se envía la petición codificada como petición HTTPS

  • IP
    IP=<dirección IP del Web-IO>

  • PORT
    PORT=<puerto para HTTP(s) del Web-IO>

  • PW
    PW=<contraseña del Web-IO>

  • COMMAND
    COMMAND=<comando a enviar al Web-IO>
    Comandos posibles: input, output, counter, outputaccess, single

  • STATE (solo con el comando outputaccess)
    STATE=<patrón de bits para los estados de conmutación a los que deben cambiar las salidas, en hexadecimal>

  • MASK (solo con el comando outputaccess
    MASK=<patrón bits de las salidas que deben ser conmutadas, en hexadecimal>

Los comandos y parámetros a transmitir bajo COMMAND se corresponden con los comandos básicos de las peticiones HTTP.

Para el envío de las peticiones HTTP, el script de PHP utiliza la biblioteca de funciones de PHP 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);
  }
?>
							
						

Estructura básica de la página web

Cross-Origin página web

La estructura HTML básica de esta página tiene el siguiente aspecto:

							
<!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>
							
						

No vamos a entrar aquí en los detalles del área de head ni sobre la información de estilos. El contenido del área de script será explicado más adelante. Importantes son el body y las denominaciones de id a través de las cuales se activan los objetos y las celdas de las tablas en las funciones de JavaScript. Con onclick se asigna al botón la función respectiva a activar. Como parámetro se transmite el número del Web-IO, seguido de los números de los contadores o de las salidas. En el caso de las salidas, el segundo parámetro indica el estado (0=OFF, 1=ON).

Siguiendo este sistema se puede adaptar el ejemplo a otros modelos de Web-IO agregando más filas en las tablas sin modificar las funciones de JavaScript.

Variables y funciones globales en JavaScript

En primer lugar hay que definir algunas variables globales.

							
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;
}
							
						

Enviar peticiones HTTP y recibir respuestas HTTP

							
// 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);
  }
}
								
							

Del desarrollo de las peticiones HTTP y respuestas HTTP se encarga la función DataRequest. Desgraciadamente Internet Explorer utiliza para el procesamiento de las peticiones HTTP mecanismos diferentes a los de otros navegadores. Por esa razón, la función comprueba en primer lugar el navegador en el que se ejecuta la página web. La petición HTTP transmitida como SendString es enviada al servidor o el Web-IO, del que también fue cargada la página web. A continuación, la respuesta, es decir la HTTP-Reply, es transmitida a la función UpdateDisplay.

Consultas cíclicas de entradas, salidas y contadores

								
// 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);
}
								
							

La función CommandLoop se inicia con el parámetro onload en la etiqueta del body, en el momento en que la página web está cargada por completo. A través de DataRequest, la función envía alternadamente las peticiones HTTP a los Web-IO para consultar las entradas, salidas y contadores y se activa ella misma de nuevo con un retardo temporal. De ese modo, se actualizan constantemente los estados de las EA con intervalos fijos.

Conectar los 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);
}
							
						

Pulsando el botón correspondiente se activa la función setOutput y se transmite el número del Web-IO y de la salida, así como el estado a conmutar. A través de la función DataRequest se envía al Web-IO la petición HTTP necesaria.

Borrar contadores

							
// 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);
}
							
						

Pulsando el botón correspondiente se activa la función clearCounter y se transmite el número del Web-IO y de la entrada.

Actualizar los contenidos de páginas web

							
// 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];
  }
}
							
						

Como respuesta a una petición HTTP, el Web-IO envía siempre el comando propiamente dicho y uno o varios parámetros separados por punto y coma. La respuesta del Web-IO transmite el script de PHP 1:1.

Para la consulta de una entrada, por ejemplo input;1

La función UpdateDisplay utiliza split para descomponer el string transmitido en un array de strings. En el ejemplo para la entrada se obtiene un array con las primeras variables de campo input y las segundas 1. Las primeras letras de las primeras variables de campo definen si la respuesta se refiere a una entrada, una salida o a los contadores.

La segunda variable de campo contiene, para la entrada o la salida, el patrón de bit que indica el estado de conmutación de las EA (Bit0=Input0, Bit1= Input1, .....). Puesto que el valor se transmite en escritura hexadecimal primero tiene que ser convertido con la función HexToInt en un número decimal.

Con un enlace de Y del valor de la entrada con la potencia al cuadrado, que se corresponde con el valor en bits de las diferentes entradas o salidas, se determina si la entrada (salida) afectada es igual a 0 o a 1, es decir si se encuentra en OFF o en ON. Esto tiene lugar en un bucle que se ejecutan en función de a la cantidad de EA.

Con la función de JavaScript document.getElementById se identifica el objeto de indicación a actualizar, que es modificado en función del estado actual de conmutación.

Los mismos mecanismos se utilizan para actualizar los contadores, si bien en este caso se suprime la conversión de hexadecimal a decimal, pues los estados de los contadores se transmiten en valores decimales.


El ejemplo es compatible con las funciones más importantes del Web-IO, que estén disponibles a través de peticiones HTTP, optimizado para Web-IO Digital 4.0 2xIn, 2xOut. Para otros modelos de Web-IO puede ser necesario adaptar la estructura de la página web y la parte de JavaScript. Encontrará una descripción detallada sobre los usos de las peticiones HTTP para los modelos de Web-IO Digital en la sinopsis de comandos de peticiones o en manual de programación para Web-IO.

Descargar el programa ejemplo

Productos