Tutorial al Web-IO digital:
Control de Web-IO digital desde una página web propia con AJAX
Los modelos de Web-IO Digital 4.0 ofrecen la posibilidad de crear una página web propia y cargarla en el Web-IO. De ese modo se puede organizar el entorno para conmutar y supervisar según las necesidades personales.
La parte principal de tales páginas web dinámicas (actualización automática) es la técnica, de consultar la información del Web-IO con ayuda de JavaScript vía peticiones HTTP y adaptar la página web ya cargada a la representación del proceso del Web-IO.
Esta técnica de programación se denomina Asynchronous JavaScript and XML, abreviado AJAX.
El siguiente ejemplo muestra la estructura de una página web muy sencilla y las funciones necesarias para mostrar los estados de las EA para Web-IO Digital 4.0 2xIn, 2xOut.
Preparativos
- Conectar la tensión para Web-IO y cablear las IO
- Conectar el Web-IO a la red
- Asignar direcciones de IP
En Web-IO, dentro de la sección Vías de comunicación >> Web-API activar la opción Permitir peticiones HTTP y habilitar las salidas a conmutar
Estructura básica de la página web propia
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, User</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="pw" type="password" maxlength="31" size="20"">
</div>
</form>
<table align="center" class="table">
<tr>
<td>input 0</td>
<td id="input0">OFF</td>
<td id="counter0">0</td>
<td>
<input class="button" onclick="clearCounter(0);" type="button" value="Clear">
</td>
<td class="borderLeft">output 0</td>
<td id="output0">OFF</td>
<td>
<input class="button" onclick="setOutput(0,1);" type="button" value="ON">
<input class="button" onclick="setOutput(0,0);" type="button" value="OFF">
</td>
</tr>
<tr class="whiteBack">
<td>input 1</td>
<td id="input1">OFF</td>
<td id="counter1">0</td>
<td>
<input class="button" onclick="clearCounter(1);" type="button" value="Clear">
</td>
<td class="borderLeft">output 1</td>
<td id="output1">OFF</td>
<td>
<input class="button" onclick="setOutput(1,1);" type="button" value="ON">
<input class="button" onclick="setOutput(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 en el body 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 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 ApplicationStep = 0;
var Interval = 500;
// 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(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(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 CommandString =’’;
var IOPassword = document.getElementById(’pw’).value;
ApplicationStep++;
switch(ApplicationStep)
{ case 1:
CommandString = ’input’;
break;
case 2:
CommandString = ’output’;
break;
case 3:
CommandString = ’counter’;
ApplicationStep = 0;
break;
}
DataRequest(CommandString + ’?PW=’ + IOPassword + ’&’);
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(OutNo, OutVal)
{ var IOPassword = document.getElementById(’pw’).value;
var CommandString = ’outputaccess’+OutNo+’?PW=’+IOPassword+’&State=OFF&’;
if(OutVal>0)
{ CommandString = ’outputaccess’+OutNo+’?PW=’+IOPassword+’&State=ON&’;
}
DataRequest(CommandString);
}
Pulsando el botón correspondiente se activa la función setOutput
y se transmite el número de las salidas y 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(CounterNo)
{ var IOPassword = document.getElementById(’pw’).value;
DataRequest(’counterclear’+CounterNo+’?PW=’+IOPassword+’&’);
}
Pulsando el botón correspondiente se activa la función clearCounter
y se transmiten los números de las entradas.
Actualizar los contenidos de páginas web
// Dynamic update of the display depending on IO State
function updateDisplay(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(’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(’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(’counter’ + i).innerHTML = ReceiveData[ReceiveData.length - MaxI + i]
}
}
}
//Display cleared Counter
if (ReceiveData[ReceiveData.length - 2].substring(0, 1) == ’c’)
{ document.getElementById(’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.
Para una consulta de entradas esto es, 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.