W&T verbindet
Interfaces für TCP/IP, Ethernet, RS-232, RS-485, USB, 20mA, Glas- und Kunststoff-LWL, http, SNMP, OPC, Modbus TCP, I/O digital, I/O analog, ISA, PCI

Applikation zum Web-IO Digital:

Web-IO Digital - mit AJAX und PHP im Browser visualisieren


Der Internet Browser ist heute Bestandteil aller modernen Betriebssysteme. Egal ob Internet Explorer, Firefox, Opera, Netscape oder Safari - beim Surfen im Internet wird der Browser als vielseitiges Anzeigeinstrument geschätzt.

Ajax und Web-IO Digital

Mit AJAX und den W&T Web-IOs kann der Browser nun auch als Anzeige- und Steuerelement für dynamische, technische Anwendungen benutzt werden.

AJAX steht für Asynchronous JavaScript and XML, wobei die Kernfunktionalität von AJAX darin besteht, auch nach Laden einer Webseite in den Browser weiter mit dem Server zu kommunizieren. Webseiten, die in Standard HTML aufgebaut werden, können zur Aktualisierung nur komplett neu geladen werden. AJAX-basierende JavaScripte hingegen können einzelne Anzeigeelemente nachträglich austauschen oder verändern.

Eine entscheidende Einschränkung dieser Technik besteht darin, dass die Kommunikation nach dem Laden einer Webseite nur mit dem Server möglich ist, von dem diese Webseite ursprünglich geladen wurde.

Für das Anzeigen von Web-IO Status bedeuted das, die Webseite muss für reine AJAX-Technik direkt aus dem Web-IO geladen werden. Somit ist es mit reiner AJAX-Technik nicht möglich, die Status mehrerer Web-IO auf einer Webseite dynamisch wiederzugeben.

Eine Alternative ist der Einsatz von PHP.

Die Webseite, welche die Web-IO Status wiedergeben soll, wird dazu von einem PHP-fähigen Webserver geladen. Um die Anzeige dynamisch weiter zu pflegen, wird dann zyklisch oder bei Bedarf ein PHP-Script aufgerufen. Dieses PHP-Script baut vom PHP-Server eine Verbindung zum Web-IO auf und fragt dort die benötigten Daten ab. Der PHP-Server gibt diese Daten dann an den Browser weiter, wo die Anzeige mittels AJAX aktualisiert wird.

Vergleich Ajax-Technik und Standard HTTP

Die im Folgenden beschriebene Web-Anwendung zeigt beispielhaft das Zusammenspiel von AJAX, PHP und Web-IO.

Sie haben noch kein Web-IO und möchten das vorgestellte Beispiel einfach mal ausprobieren?

Kein Problem: Wir stellen Ihnen das Web-IO Digital 2xInput, 2xOutput gerne kostenlos für 30 Tage zur Verfügung. Einfach Musterbestellung ausfüllen, wir liefern das Web-IO zum Test auf offene Rechnung. Wenn Sie das Gerät innerhalb von 30 Tagen zurück schicken, schreiben wir die Rechnung komplett gut.

Zur Musterbestellung

Vorbereitungen

Sie haben Ihr Web-IO Digital bereits

1. Das PHP-Script

Dieses Script ist das Kernstück der hier beschriebenen Technik. Es wird bei Bedarf mittels eines AJAX-Requests vom Browser aus aufgerufen. Dabei werden über die URL alle benötigten Parameter übergeben:

IP IP-Adresse des Web-IO
PORT TCP-Port des Web-IO (normaler Weise 80)
COMMAND mögliche Kommandos sind: output, input oder counter, wobei dem eigentlichen Kommando noch die Nummer des Inputs oder Outputs folgen kann. Das Web-IO gibt den Status der Inputs oder Outputs zurück.
Als weiteres Kommando können mit outputaccess die Outputs gesetzt werden
PW Administrator oder Operator Passwort des Web-IO
MASK gibt in hexadezimaler Schreibweise an, welche Outputs gesetzt werden sollen (nur bei outputaccess)
STATE gibt in hexadezimaler Schreibweise an, in welchen Zustand die Outputs gesetzt werden sollen (nur bei 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);
						}
					?>

Dieses Script wird auf den Server unter webiorequest.php gespeichert.

2. Zusammenstellen der verschiedenen Bedienelemente und Anzeigeobjekte auf dereigentlichen Webseite

Bedienelemente AJAX

Bei der Benennung der einzelnen Objekte bzw. der aufzurufenden Funktionen ist es hilfreich, sinngebende Namen zu verwenden.

3. HTML-Grundaufbau der Webseite

Platzieren der Bedien- und Anzeigeelemente

Zur besseren Strukturierung werden die einzelnen Elemente in Tabellen untergebracht und das Ganze als Formular deklariert.


						<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. Globale JavaScript Deklarationen

Allgemeine Variablen und Funktionen

Obwohl die Webseite für das Web-IO 2xDigital Input, 2xDigital Output aufgebaut ist, sind die JavaScripte für Web-IOs mit mehr IOs vorbereitet. Deshalb auch die Funktion HexToInt, die hexadezimale Strings in Ganzzahlen wandelt.

Die Variable SendString wird später für den Datenversand an das Web-IO genutzt.


								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. Bedienung durch den Anwender verarbeiten

In Abhängigkeit davon, welches Bedienelement der Webseite der Anwender angeklickt oder verändert hat, wird die Variable SendString mit dem entsprechenden Kommando gefüllt.

Setzen der Outputs

Das Setzen der Outputs wird dem Anwender über zwei Checkboxen cb_output ermöglicht. Bei Aufruf der Funktion wird die Nr. des Outputs übergeben.

Die Funktion DataRequest, die abschließend aufgerufen wird, dient dem Datenaustausch mit dem PHP-Server und damit mit auch mit dem Web-IO und ist im weiteren Verlauf noch näher beschrieben.


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

Den Status der Outputs und Inputs kann der Anwender durch Anklicken des zugehörigen Buttons anfordern.


							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+'&');
								}
							
Counter abfragen löschen

Auch die Zählerstände der Input-Counter lassen sich abfragen bzw. löschen. Als Parameter wird die Nr. des Counters übergeben, der gelesen bzw. gelöscht werden soll. Wenn kein Parameter übergeben wird, liest bzw. löscht das Web-IO alle 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. Kommunikation mit dem Web-IO

Datenaustausch mit dem Web-IO und Aktualisierung der Webseite nachdem diese bereits geladen wurde
  • Die hier vorgestellte Funktion beinhaltet das, was AJAX ausmacht.
  • Die Funktion DataRequest sendet im Hintergrund, für den Anwender unsichtbar, die ausgewählten und in SendString übergebenen Kommandos an das Web-IO. Die integrierte Funktion DataReceived nimmt die Antworten des Web-IO entgegen.
  • Die Antworten des Web-IO haben je nach Type einen spezifischen Aufbau.
  • Für die Outputs: output;<Binärwert des Outputstatus im hexadezimalen Format>
  • Für die Inputs: input;<Binärwert des Outputstatus im hexadezimalen Format>
  • Für die Counter: counterx;<dezimaler Zählerstand>
  • oder counter;<dezimaler Zählerstand 0 >; <dezimaler Zählerstand 0 >; ...... wenn alle Counter auf einmal gelesen werden sollen.
  • Je nach empfangener Antwort verzweigt die Empfangsfunktion in den entsprechenden Teil und aktualisiert die Anzeige der Objekte im Browserfenster.

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

Auch wenn das gezeigte Beispiel für das Web-IO 2x Digital Input, 2x Digital Output zugeschnitten ist, ist die Funktion DataRequest auch für Web-IO mit mehr IOs vorbereitet.

7. Polling

Zyklisches Abfragen bestimmter Werte

Um auch eine vollautomatische Aktualisierung der Anzeige zu ermöglichen, wird die JavaScript Interval Funktion benutzt. In Abhängigkeit der Checkboxen für Output-, Input- und Counter-Polling werden die entsprechenden Information im eingestellten Intervall vom Web-IO abgerufen.


							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+'&');
									}
								}
							

Das gewünschte Intervall kann in das entsprechende Textfeld eingegeben werden und wird durch Anklicken des Set Interval Button angepasst.


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

Das Beispiel unterstützt alle gängigen Funktionen des Web-IO, optimiert für das Web-IO 2x Digital Input, 2x Digital Output. Für die anderen Web-IO Modelle müssen ggf. Anpassungen an der Beispiel-Webseite vorgenommen werden. Weitere Programmbeispiele zur Socket-Programmierung finden Sie auf den Tool-Seiten zum Web-IO. Eine detaillierte Beschreibung zu den Kommandos der Web-IO Digital Modelle finden Sie im Referenzhandbuch.

Programmbeispiel herunterladen

Sie haben noch kein Web-IO und möchten das vorgestellte Beispiel einfach mal ausprobieren?

Kein Problem: Wir stellen Ihnen das Web-IO Digital 2xInput, 2xOutput gerne kostenlos für 30 Tage zur Verfügung. Einfach Musterbestellung ausfüllen, wir liefern das Web-IO zum Test auf offene Rechnung. Wenn Sie das Gerät innerhalb von 30 Tagen zurück schicken, schreiben wir die Rechnung komplett gut.

Zur Musterbestellung