W&T collega
Adattatori per TCP/IP, Ethernet, RS-232, RS-485, USB, 20 mA, Fibra ottica di vetro e plastica, http, SNMP, OPC, Modbus TCP, I/O digitale, I/O analogico, ISA, PCI

Applicazione relativa al Web-IO digitale:

Visualizzazione nel browser con AJAX e PHP del Web-IO digitale


Il browser Internet è oggi parte integrante di tutti i moderni sistemi operativi. Che si tratti di Internet Explorer, Firefox, Opera, Netscape o Safari, nella navigazione in Internet il browser viene apprezzato come strumento di visualizzazione versatile.

Ajax e Web-IO digitale

Con AJAX e con i Web-IO W&T il browser ora può essere utilizzato anche come elemento di visualizzazione e di controllo per applicazioni tecniche dinamiche.

AJAX è l’abbreviazione di Asynchronous JavaScript and XML, dove la funzionalità chiave di AJAX consiste nel continuare a comunicare con il server anche dopo il caricamento di una pagina web nel browser. Le pagine web con struttura HTML standard possono essere caricate di nuovo per l’aggiornamento solo in modo completo. I JavaScript basati su AJAX possono al contrario sostituire o modificare successivamente singoli elementi di visualizzazione.

Una grossa limitazione di questa tecnica è rappresentata dalla possibilità di comunicare dopo il caricamento di una pagina web solo con il server da cui questa pagina web è stata caricata inizialmente.

Per la visualizzazione degli stati dei Web-IO ciò significa che per la pura tecnica AJAX la pagina web deve essere caricata direttamente dal Web-IO. In tal modo non è possibile con la pura tecnica AJAX riprodurre in modo dinamico su una pagina web gli stati di più Web-IO.

Un’alternativa è rappresentata dall’impiego di PHP..

La pagina web che deve riprodurre gli stati dei Web-IO viene a tale scopo caricata da un server web PHP compatibile. Per continuare a trattare dinamicamente la visualizzazione viene quindi richiamato ciclicamente o all’occorrenza uno script PHP. Questo script PHP crea a partire dal server PHP un collegamento al Web-IO, dove richiede i dati necessari. Il server PHP inoltra quindi questi dati al browser dove la visualizzazione viene aggiornata mediante AJAX.

Confronto tecnica Ajax e HTTP standard

L’applicazione web descritta di seguito mostra ad esempio l’interazione di AJAX, PHP e Web-IO.

Non disponete ancora di un Web-IO e desiderate semplicemente provarne il funzionamento come nell’esempio illustrato?

Nessun problema: vi mettiamo a disposizione gratuitamente per 30 giorni il Web-IO digitale 2x input, 2x output. Non dovete far altro che compilare l’ordinazione del campione e vi forniremo il Web-IO in prova in conto aperto. Se ci restituite l’apparecchio entro 30 giorni, vi accreditiamo completamente la fattura.

All’ordinazione del campione

Preparativi

Avete già alimentato con corrente

1. Lo script PHP

Questo script è il nucleo della tecnica qui descritta. All’occorrenza viene richiamato dal browser mediante una richiesta AJAX. Durante questa operazione vengono forniti attraverso l’URL tutti i parametri necessari:

IP indirizzo IP del Web-IO
PORT porta TCP del Web-IO (modo normale 80)
COMMAND comandi possibili: output, input o counter, dove al comando vero e proprio può seguire ancora il numero dell’input o dell’output. Il Web-IO restituisce lo stato degli input o degli output.
Come ulteriore comando gli output possono essere impostati con outputaccess
PW password amministratore od operatore del Web-IO
MASK indica con scrittura esadecimale gli output che devono essere impostati (solo con outputaccess)
STATE indica con scrittura esadecimale in quale stato gli output devono essere impostati (solo con outputaccess)

					<?php
						header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
						header("Last-Modified: " . gmdate("D,d M Y H:i:s") . " GMT");
						header("Cache-Control: no-store, no-cache, must-revalidate");
						header("Cache-Control: post-check=0, pre-check=0",false);
						header("Pragma: no-cache");
						parse_str($_SERVER['QUERY_STRING']);
						$fp=fsockopen($IP, $PORT, $errno, $error, 5);
						if (!$fp)
						{ printf("ERROR"); }
						else
						{ if ($COMMAND == "outputaccess")
							{  if ($MASK == "") {$MASK="0FFF";}
							fputs($fp, "GET /".$COMMAND."?PW=".$PW."&Mask=".$MASK."&State=".$STATE."&");
							}
							else
							{ fputs($fp, "GET /".$COMMAND."?PW=".$PW."&");
							}
							do
							{ $char=fgetc($fp);
							if($char!=chr(0))
							{ echo $char;
							}
							}
							while($char!=chr(0));
							fclose($fp);
						}
					?>

Questo script viene memorizzato sul server sotto webiorequest.php.

2. Collocazione dei diversi elementi di comando e oggetti di visualizzazione nell’effettiva pagina web

Elementi di comando AJAX

Nella denominazione dei singoli oggetti o delle funzioni da richiamare è utile utilizzare nomi che ne riprendono il significato.

3. Struttura di base HTML della pagina web

Collocazione degli elementi di comando e visualizzazione

Per una migliore strutturazione i singoli elementi vengono sistemati in tabelle e il tutto indicato come modulo.


						<html>
							<head>
								<title>Web-IO AJAX-Client</title>
								<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
								<STYLE type=text/css>
									TD {COLOR: #000000; FONT-FAMILY:
										Verdana,Arial,Helvetica; FONT-SIZE: 10pt; }
									</STYLE>
							</head>
								<body bgcolor="#FFFFFF" text="#000000" link="#000000">
								<form name="ioform">
									<table width="500" border="1" height="144" bgcolor="#CCCCCC">
									<tr>
									<td>
										<table width="500">
										<tr>

											<td colspan="6"><b>Input/Output Control </b></td>
										</tr>
										<tr>

											<td width="100">
											<input type="checkbox" name="cb_output" onclick="setOutput(0)">Output 0
											</td>
											<td width="100">
											<input type="checkbox" name="cb_input">Input 0
											</td>
											<td width="100">
											<div align="right">Counter 0 </div>
											</td>
											<td width="*" bgcolor="#FFFFFF" id="counter0">
											</td>
											<td width="55">
											<input type="button" value="Read" onclick="getCounter(0)">
											</td>
											<td width="55">
											<input type="button" value="Clear" onclick="clearCounter(0)">
											</td>
										</tr>
										<tr>

											<td width="100">
											<input type="checkbox" name="cb_output" onclick="setOutput(1)">
											Output 1
											</td>
											<td width="100">
											<input type="checkbox" name="cb_input"> Input 1
											</td>
											<td width="100">
											<div align="right">Counter 1 </div>
											</td>
											<td width="*" bgcolor="#FFFFFF" id="counter1">
											</td>
											<td width="55">
											<input type="button" value="Read" onclick="getCounter(1)">
											</td>
											<td width="55">
											<input type="button" value="Clear" onclick="clearCounter(1)">
											</td>
										</tr>
										<tr>

											<td width="100" height="29">
											<input type="button" value="Read all" onclick="getOutputs()">
											</td>
											<td width="100" height="29">
											<input type="button" value="Read all" onclick="getInputs()">
											</td>
											<td width="100" height="29">
											<div align="right">Counter all </div>
											</td>
											<td width="*" height="29">
											</td>
											<td width="55" height="29">
											<input type="button" value="Read" onclick="getCounter()">
											</td>
											<td width="55" height="29">
											<input type="button" value="Clear" onclick="clearCounter()">
											</td>
										</tr>
										<tr>

											<td width="100">
											<input type="checkbox" name="cb_output_polling">Polling
											</td>
											<td width="100">
											<input type="checkbox" name="cb_input_polling">
											Polling
											</td>
											<td width="100">
											<div align="right">
												<input type="button" value="Set Interval" onclick="setPolInterval()">
											</div>
											</td>
											<td width="*" >
											<input type="text" name="ed_interval" value="500" maxlength="6" size="9">
											</td>
											<td colspan="2">
											<input type="checkbox" name="cb_counter_polling">
											Polling
											</td>
										</tr>
										</table>
									</td>
									</tr>
								</table>
								<table width="500" border="1" bgcolor="#CCCCCC" >
									<tr>
									<td height="35">

										<table width="500">
										<tr>

											<td width="188">IP Address</td>
											<td width="149">Port</td>
											<td width="147">Password</td>
										</tr>
										<tr>

											<td width="188">
											<input type="text" name="ed_ip">
											</td>
											<td width="149">
											<input type="text" name="ed_port" maxlength="5" size="15">
											</td>
											<td width="147">
											<input type="text" name="ed_password">
											</td>
										</tr>
										</table>
									</td>
									</tr>
								</table>
								</form>
								......
								

4. Dichiarazioni JavaScript globali

Variabili e funzioni generali

Sebbene la pagina web sia costruita per il Web-IO 2x input digitale, 2x output digitale, i JavaScript sono stati predisposti per i Web-IO con più IO. Pertanto anche la funzione HexToInt che converte le stringhe esadecimali in numeri interi.

La variabile SendString viene utilizzata successivamente per l’invio di dati al Web-IO.


								var MAXIO=2;
								var SendString;

								function HexToInt(HexStr)
									{
									var TempVal;
									var HexVal=0;
									for( 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;
									}

								.......
								

5. Elaborazione dell’utilizzo da parte dell’utente

In base all’elemento di comando della pagina web su cui ha fatto clic o che ha modificato l’utente, la variabile SendString viene riempita con il corrispondente comando.

Impostazione degli output

L’impostazione degli output è resa possibile all’utente da due caselle di spunta cb_output. Al richiamo della funzione viene fornito il n. dell’output.

La funzione DataRequest, che viene richiamata alla fine, serve allo scambio di dati con il server PHP e in tal modo anche con il Web-IO; viene descritta dettagliatamente più avanti.


								function setOutput(OutputNr)
									{
									if (ioform.cb_output[OutputNr].checked==true)
										{ SendString='webiorequest.php?IP='+ioform.ed_ip.value
										+'&PORT='+ioform.ed_port.value
										+'&COMMAND=outputaccess&PW='+ioform.ed_password.value
										+'&MASK='+Math.pow(2,OutputNr)
										+'&STATE='+Math.pow(2,OutputNr)+'&';
										}
									else
										{ SendString='webiorequest.php?IP='+ioform.ed_ip.value
										+'&PORT='+ioform.ed_port.value
										+'&COMMAND=outputaccess&PW='+ioform.ed_password.value
										+'&MASK='+Math.pow(2,OutputNr)
										+'&STATE=0&';
										}
									DataRequest(SendString);
									}
							
Interrogazione dello stato degli output/input

L’utente può richiedere lo stato degli output e degli input facendo clic sul relativo pulsante.


							function getOutputs()
								{
								DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
								+'&COMMAND=output&PW='+ioform.ed_password.value+'&');
								}
							

							function getInputs()
								{
								DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
								+'&COMMAND=input&PW='+ioform.ed_password.value+'&');
								}
							
Interrogazione/cancellazione dei counter

È possibile interrogare o cancellare anche gli stati dei counter degli input. Come parametro viene fornito il n. del counter che deve essere letto o cancellato. Se non viene fornito alcun parametro, il Web-IO legge o cancella tutti i counter.


							function getCounter(CounterNr)
								{
								if (CounterNr==undefined)
									{ DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
									+'&COMMAND=counter&PW='+ioform.ed_password.value+'&');
									}
								else
									{ DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
									+'&COMMAND=counter'+CounterNr+'&PW='+ioform.ed_password.value+'&');
									}
								}
							

								function clearCounter(CounterNr)
									{
									if (CounterNr==undefined)
										{ DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
										+'&COMMAND=counterclear&PW='+ioform.ed_password.value+'&');
										}
									else
										{ DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
										+'&COMMAND=counterclear'+CounterNr+'&PW='+ioform.ed_password.value+'&');
										}
									}
							

6. Comunicazione con il Web-IO

Scambio di dati con il Web-IO e aggiornamento della pagina web dopo il suo caricamento
  • La funzione qui presentata contiene ciò che costituisce AJAX.
  • La funzione DataRequest invia al Web-IO, senza che ciò sia visibile per l’utente, i comandi selezionati e forniti in SendString. La funzione integrata DataReceived riceve le risposte del Web-IO.
  • Le risposte del Web-IO hanno una struttura specifica in base al tipo.
  • Per gli output: output;<valore binario dello stato degli output in formato esadecimale>
  • Per gli input: input;<valore binario dello stato degli input in formato esadecimale>
  • Per i counter: counterx;<stato del conteggio decimale>
  • oppure counter;<stato del conteggio decimale 0 >; <stato del conteggio decimale 0 >; ... se tutti i counter devono essere letti in un’unica volta.
  • In base alla risposta ricevuta la funzione di ricezione si ramifica corrispondentemente e aggiorna la visualizzazione degli oggetti nella finestra del browser.

							function DataRequest(SendString)
								{
								var xmlHttp;
								try
								{  // Internet Explorer
								if( window.ActiveXObject )
								{  xmlHttp = new ActiveXObject("Microsoft.XMLHTTP" );
								}
								// Mozilla, Opera und Safari
								else if(window.XMLHttpRequest)
									{  xmlHttp = new XMLHttpRequest();
									}
									}
									// loading of xmlhttp object failed
									catch( excNotLoadable )
									{  xmlHttp = false;
									alert("no knowen browser");
									}
									if (xmlHttp)
									{  xmlHttp.onreadystatechange = DataReceived;
									xmlHttp.open("GET",SendString, true);
									xmlHttp.setRequestHeader("Cache-Control","no-store, no-cache, must-revalidate");
									xmlHttp.setRequestHeader("Expires","Sat, 05 Nov 2005 00:00:00 GMT");
									xmlHttp.setRequestHeader("Pragma","no-cache");
									xmlHttp.send(null);
									}
									function DataReceived()
									{  var HexVal;
									var ReceiveStr;
									if (xmlHttp.readyState == 4)
									{  if (xmlHttp.status == 200)
											{  ReceiveStr = xmlHttp.responseText;
											//Input handling
											if (ReceiveStr.substring(0,5)=='input')
											{  HexVal=HexToInt(ReceiveStr.substring(6,10));
											for (i=0;i<MAXIO;i++)
											{
											if ((HexVal & Math.pow(2,i)) == Math.pow(2,i))
												{  ioform.cb_input[i].checked = true;
												}
											else
											{  ioform.cb_input[i].checked = false;
											}
											}
											}
											//Output handling
											if (ReceiveStr.substring(0,6)=='output')
											{  HexVal=HexToInt(ReceiveStr.substring(7,11));
											for (i=0;i<MAXIO;i++)
											{
											if((HexVal & Math.pow(2,i)) == Math.pow(2,i))
												{ioform.cb_output[i].checked = true;
													}
													else
													{ioform.cb_output[i].checked = false;
													}
											}
											}
											//Counter handling
											if (ReceiveStr.substring(0,7)=='counter')
											{
											var slength=ReceiveStr.length;
											if (ReceiveStr.substring(7,8)==';')
											{  countervalue=ReceiveStr.split(';');
													for (i=0;i<MAXIO;i++)
													{
													document.getElementById('counter'+i).innerHTML ='<a>'+countervalue[i+1]+'<\/a>';
													}
											}
											else
											{  if (ReceiveStr.substring(9,10)==';')
													{  i=(ReceiveStr.substring(7,9));
													document.getElementById('counter'+i).innerHTML = '<a>'+ReceiveStr.substring(10,slength)+'<\/a>';
													}
												else
													{  i=(ReceiveStr.substring(7,8));
													document.getElementById('counter'+i).innerHTML = '<a>'+ReceiveStr.substring(9,slength)+'<\/a>';
													}
											}
										}
									}
								}
							}
						}
							

Anche se l’esempio mostrato è improntato per il Web-IO 2x input digitale, 2x output digitale, la funzione DataRequest è predisposta anche per il Web-IO con più IO.

7. Polling

Interrogazione ciclica di determinati valori

Per rendere possibile anche un aggiornamento completamente automatico della visualizzazione viene utilizzata la funzione JavaScript Interval. In base alle caselle di spunta per il polling degli output, degli input e dei counter le corrispondenti informazioni vengono interrogate dal Web-IO nell’intervallo impostato.


							var pollingtimer = window.setInterval("Polling()", 500);
							function Polling()
								{
								if (ioform.cb_output_polling.checked==true)
									{
									DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
									+'&COMMAND=output&PW='+ioform.ed_password.value+'&');
									}
								if (ioform.cb_input_polling.checked==true)
									{
									DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
									+'&COMMAND=input&PW='+ioform.ed_password.value+'&');
									}
								if (ioform.cb_counter_polling.checked==true)
									{
									DataRequest('webiorequest.php?IP='+ioform.ed_ip.value+'&PORT='+ioform.ed_port.value
									+'&COMMAND=counter&PW='+ioform.ed_password.value+'&');
									}
								}
							

L’intervallo desiderato può essere immesso nel corrispondente campo di testo e viene adattato facendo clic sul pulsante Set Interval.


							function setPolInterval()
								{
								var intervaltime=parseInt(ioform.ed_interval.value)
								clearInterval(pollingtimer);
								pollingtimer = window.setInterval("Polling()",intervaltime);
								}
							

L’esempio supporta tutte le funzioni comuni del Web-IO, ottimizzato per il Web-IO 2x input digitale, 2x output digitale. Per gli altri modelli di Web-IO devono essere eventualmente apportati adattamenti alla pagina web esempio. Ulteriori esempi di programma per la programmazione socket sono riportati nelle pagine dei tool relative al Web-IO. Una descrizione dettagliata relativa ai comandi dei modelli Web-IO digitali è riportata nel manuale di riferimento.

Download esempio di programma

Non disponete ancora di un Web-IO e desiderate semplicemente provarne il funzionamento come nell’esempio illustrato?

Nessun problema: vi mettiamo a disposizione gratuitamente per 30 giorni il Web-IO digitale 2x input, 2x output. Non dovete far altro che compilare l’ordinazione del campione e vi forniremo il Web-IO in prova in conto aperto. Se ci restituite l’apparecchio entro 30 giorni, vi accreditiamo completamente la fattura.

All’ordinazione del campione