538 lines
19 KiB
Java
538 lines
19 KiB
Java
package de.opcua.app.rest;
|
|
|
|
import com.sun.net.httpserver.HttpExchange;
|
|
import com.sun.net.httpserver.HttpHandler;
|
|
import java.io.IOException;
|
|
|
|
public class HelpPageHandler implements HttpHandler {
|
|
|
|
@Override
|
|
public void handle(HttpExchange exchange) throws IOException {
|
|
String path = exchange.getRequestURI().getPath();
|
|
String query = exchange.getRequestURI().getQuery();
|
|
|
|
// Determine language from query parameter or Accept-Language header
|
|
String lang = "en"; // default
|
|
if (query != null && query.contains("lang=de")) {
|
|
lang = "de";
|
|
} else if (query != null && query.contains("lang=en")) {
|
|
lang = "en";
|
|
} else {
|
|
String acceptLang = exchange.getRequestHeaders().getFirst("Accept-Language");
|
|
if (acceptLang != null && acceptLang.toLowerCase().startsWith("de")) {
|
|
lang = "de";
|
|
}
|
|
}
|
|
|
|
String html = buildHelpPage(lang);
|
|
byte[] bytes = html.getBytes("UTF-8");
|
|
|
|
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
|
|
exchange.sendResponseHeaders(200, bytes.length);
|
|
exchange.getResponseBody().write(bytes);
|
|
exchange.getResponseBody().close();
|
|
}
|
|
|
|
private String buildHelpPage(String lang) {
|
|
if ("de".equals(lang)) {
|
|
return buildGermanHelp();
|
|
} else {
|
|
return buildEnglishHelp();
|
|
}
|
|
}
|
|
|
|
private String buildEnglishHelp() {
|
|
return "<!DOCTYPE html>" +
|
|
"<html lang=\"en\">" +
|
|
"<head>" +
|
|
"<meta charset=\"UTF-8\">" +
|
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" +
|
|
"<title>OPC UA API Documentation</title>" +
|
|
"<style>" +
|
|
":root{--bg:#fff;--text:#1c1c1e;--border:#e5e5ea;--code-bg:#f5f5f7;--blue:#007aff;--green:#34c759;--orange:#ff9500}" +
|
|
"@media(prefers-color-scheme:dark){:root{--bg:#000;--text:#fff;--border:#38383a;--code-bg:#1c1c1e}}" +
|
|
"*{margin:0;padding:0;box-sizing:border-box}" +
|
|
"body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Text',Arial,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;padding:20px}" +
|
|
".container{max-width:1200px;margin:0 auto}" +
|
|
"header{border-bottom:2px solid var(--blue);padding-bottom:20px;margin-bottom:40px}" +
|
|
"h1{font-size:32px;font-weight:700;margin-bottom:10px}" +
|
|
".lang-switch{float:right}" +
|
|
".lang-switch a{color:var(--blue);text-decoration:none;margin:0 5px}" +
|
|
"h2{font-size:24px;font-weight:600;margin:30px 0 15px;color:var(--blue)}" +
|
|
"h3{font-size:18px;font-weight:600;margin:20px 0 10px}" +
|
|
".endpoint{background:var(--code-bg);padding:15px;border-radius:8px;margin:15px 0;border-left:4px solid var(--blue)}" +
|
|
".method{display:inline-block;padding:4px 8px;border-radius:4px;font-weight:600;font-size:12px;margin-right:10px}" +
|
|
".method.get{background:var(--green);color:#fff}" +
|
|
".method.post{background:var(--orange);color:#fff}" +
|
|
"pre{background:var(--code-bg);padding:15px;border-radius:8px;overflow-x:auto;margin:10px 0}" +
|
|
"code{font-family:'SF Mono',Monaco,'Courier New',monospace;font-size:14px}" +
|
|
".note{background:#fff3cd;border-left:4px solid var(--orange);padding:15px;margin:15px 0;border-radius:4px}" +
|
|
"table{width:100%;border-collapse:collapse;margin:15px 0}" +
|
|
"th,td{padding:12px;text-align:left;border-bottom:1px solid var(--border)}" +
|
|
"th{font-weight:600;background:var(--code-bg)}" +
|
|
".toc{background:var(--code-bg);padding:20px;border-radius:8px;margin:20px 0}" +
|
|
".toc ul{list-style:none;padding-left:0}" +
|
|
".toc li{margin:8px 0}" +
|
|
".toc a{color:var(--blue);text-decoration:none}" +
|
|
"</style>" +
|
|
"</head>" +
|
|
"<body>" +
|
|
"<div class=\"container\">" +
|
|
"<header>" +
|
|
"<div class=\"lang-switch\">" +
|
|
"<a href=\"?lang=en\">English</a> | <a href=\"?lang=de\">Deutsch</a>" +
|
|
"</div>" +
|
|
"<h1>🔧 OPC UA REST API Documentation</h1>" +
|
|
"<p>Complete reference for integrating with the OPC UA HTTP API</p>" +
|
|
"</header>" +
|
|
|
|
"<div class=\"toc\">" +
|
|
"<h2>Table of Contents</h2>" +
|
|
"<ul>" +
|
|
"<li><a href=\"#overview\">Overview</a></li>" +
|
|
"<li><a href=\"#authentication\">Authentication</a></li>" +
|
|
"<li><a href=\"#endpoints\">API Endpoints</a></li>" +
|
|
"<li><a href=\"#integration\">3rd Party Integration</a></li>" +
|
|
"<li><a href=\"#examples\">Complete Examples</a></li>" +
|
|
"<li><a href=\"#errors\">Error Handling</a></li>" +
|
|
"</ul>" +
|
|
"</div>" +
|
|
|
|
"<h2 id=\"overview\">Overview</h2>" +
|
|
"<p>The OPC UA HTTP API provides RESTful access to OPC UA server data. All endpoints accept and return JSON.</p>" +
|
|
"<p><strong>Base URL:</strong> <code>http://localhost:8081</code></p>" +
|
|
"<p><strong>Content-Type:</strong> <code>application/json</code></p>" +
|
|
|
|
"<h2 id=\"authentication\">Authentication</h2>" +
|
|
"<p>Currently, no authentication is required for local access. For production deployment, use HTTPS with client certificates.</p>" +
|
|
|
|
"<h2 id=\"endpoints\">API Endpoints</h2>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method get\">GET</span> /api/status</h3>" +
|
|
"<p>Get OPC UA connection status</p>" +
|
|
"<h4>Response:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"connected\": true," +
|
|
" \"timestamp\": 1707989123456" +
|
|
"}</code></pre>" +
|
|
"<h4>Example:</h4>" +
|
|
"<pre><code>const response = await fetch('/api/status');" +
|
|
"const data = await response.json();" +
|
|
"console.log('Connected:', data.connected);</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method post\">POST</span> /api/read</h3>" +
|
|
"<p>Read a value from an OPC UA node</p>" +
|
|
"<h4>Request Body:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"nodeId\": \"ns=2;s=Temperature\"" +
|
|
"}</code></pre>" +
|
|
"<h4>Response:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"success\": true," +
|
|
" \"value\": \"25.5\"," +
|
|
" \"timestamp\": 1707989123456" +
|
|
"}</code></pre>" +
|
|
"<h4>Example:</h4>" +
|
|
"<pre><code>const response = await fetch('/api/read', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({nodeId: 'ns=2;s=Temperature'})" +
|
|
"});" +
|
|
"const data = await response.json();" +
|
|
"console.log('Temperature:', data.value);</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method post\">POST</span> /api/write</h3>" +
|
|
"<p>Write a value to an OPC UA node</p>" +
|
|
"<h4>Request Body:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"nodeId\": \"ns=2;s=SetPoint\"," +
|
|
" \"value\": \"30.0\"" +
|
|
"}</code></pre>" +
|
|
"<h4>Response:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"success\": true," +
|
|
" \"written\": true" +
|
|
"}</code></pre>" +
|
|
"<h4>Example:</h4>" +
|
|
"<pre><code>const response = await fetch('/api/write', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({" +
|
|
" nodeId: 'ns=2;s=SetPoint'," +
|
|
" value: '30.0'" +
|
|
" })" +
|
|
"});" +
|
|
"const data = await response.json();" +
|
|
"console.log('Write successful:', data.written);</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method post\">POST</span> /api/browse</h3>" +
|
|
"<p>Browse OPC UA node hierarchy</p>" +
|
|
"<h4>Request Body:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"nodeId\": \"ns=2;s=Folder\" // Optional, omit for root" +
|
|
"}</code></pre>" +
|
|
"<h4>Response:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"success\": true," +
|
|
" \"children\": [" +
|
|
" {" +
|
|
" \"displayName\": \"Temperature\"," +
|
|
" \"nodeId\": \"ns=2;s=Temperature\"" +
|
|
" }" +
|
|
" ]" +
|
|
"}</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method post\">POST</span> /api/browse-full</h3>" +
|
|
"<p>Browse complete OPC UA tree (server-side recursive)</p>" +
|
|
"<h4>Request Body:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"maxDepth\": 5" +
|
|
"}</code></pre>" +
|
|
"<h4>Response:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"success\": true," +
|
|
" \"tree\": [...nested nodes...]," +
|
|
" \"duration\": 1234," +
|
|
" \"maxDepth\": 5" +
|
|
"}</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<h2 id=\"integration\">3rd Party System Integration</h2>" +
|
|
"<p>Use the API to integrate OPC UA data with external systems.</p>" +
|
|
|
|
"<h3>Example: Send data to external REST API</h3>" +
|
|
"<pre><code>// Read from OPC UA" +
|
|
"const opcResponse = await fetch('/api/read', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({nodeId: 'ns=2;s=Temperature'})" +
|
|
"});" +
|
|
"const opcData = await opcResponse.json();" +
|
|
"\n" +
|
|
"// Send to external system" +
|
|
"await fetch('https://api.example.com/data', {" +
|
|
" method: 'POST'," +
|
|
" headers: {" +
|
|
" 'Content-Type': 'application/json'," +
|
|
" 'Authorization': 'Bearer YOUR_TOKEN'" +
|
|
" }," +
|
|
" body: JSON.stringify({" +
|
|
" sensor: 'temperature'," +
|
|
" value: opcData.value," +
|
|
" timestamp: new Date().toISOString()" +
|
|
" })" +
|
|
"});</code></pre>" +
|
|
|
|
"<h3>Example: Login Script with Session Storage</h3>" +
|
|
"<pre><code>// Login to external system" +
|
|
"const loginResponse = await fetch('https://api.example.com/auth/login', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({" +
|
|
" username: 'user'," +
|
|
" password: 'secret'" +
|
|
" })" +
|
|
"});" +
|
|
"const session = await loginResponse.json();" +
|
|
"\n" +
|
|
"// Store session for later use" +
|
|
"store.set('externalSession', session.token);" +
|
|
"store.set('externalExpiry', session.expiresAt);" +
|
|
"\n" +
|
|
"// Use in subsequent requests" +
|
|
"const token = store.get('externalSession');" +
|
|
"await fetch('https://api.example.com/data', {" +
|
|
" headers: {'Authorization': 'Bearer ' + token}" +
|
|
"});</code></pre>" +
|
|
|
|
"<h2 id=\"examples\">Complete Examples</h2>" +
|
|
|
|
"<h3>Polling Loop</h3>" +
|
|
"<pre><code>async function pollTemperature() {" +
|
|
" const response = await fetch('/api/read', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({nodeId: 'ns=2;s=Temperature'})" +
|
|
" });" +
|
|
" const data = await response.json();" +
|
|
" " +
|
|
" if (data.success) {" +
|
|
" console.log('Temperature:', data.value);" +
|
|
" " +
|
|
" // Send to external system" +
|
|
" await fetch('https://api.example.com/metrics', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({" +
|
|
" metric: 'temperature'," +
|
|
" value: parseFloat(data.value)" +
|
|
" })" +
|
|
" });" +
|
|
" }" +
|
|
"}" +
|
|
"\n" +
|
|
"// Poll every 5 seconds" +
|
|
"setInterval(pollTemperature, 5000);</code></pre>" +
|
|
|
|
"<h3>Write with Validation</h3>" +
|
|
"<pre><code>async function setSetpoint(value) {" +
|
|
" // Validate" +
|
|
" if (value < 0 || value > 100) {" +
|
|
" console.error('Value out of range');" +
|
|
" return;" +
|
|
" }" +
|
|
" " +
|
|
" // Write to OPC UA" +
|
|
" const response = await fetch('/api/write', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({" +
|
|
" nodeId: 'ns=2;s=SetPoint'," +
|
|
" value: value.toString()" +
|
|
" })" +
|
|
" });" +
|
|
" " +
|
|
" const result = await response.json();" +
|
|
" if (result.success && result.written) {" +
|
|
" console.log('Setpoint updated to', value);" +
|
|
" } else {" +
|
|
" console.error('Write failed');" +
|
|
" }" +
|
|
"}</code></pre>" +
|
|
|
|
"<h2 id=\"errors\">Error Handling</h2>" +
|
|
"<h3>Error Response Format:</h3>" +
|
|
"<pre><code>{" +
|
|
" \"success\": false," +
|
|
" \"error\": \"Error message\"" +
|
|
"}</code></pre>" +
|
|
|
|
"<h3>Common Errors:</h3>" +
|
|
"<table>" +
|
|
"<tr><th>Status</th><th>Error</th><th>Solution</th></tr>" +
|
|
"<tr><td>503</td><td>OPC UA not connected</td><td>Check OPC UA connection</td></tr>" +
|
|
"<tr><td>400</td><td>Invalid nodeId</td><td>Verify node ID format</td></tr>" +
|
|
"<tr><td>500</td><td>Read/Write failed</td><td>Check node permissions</td></tr>" +
|
|
"</table>" +
|
|
|
|
"<div class=\"note\">" +
|
|
"<strong>💡 Tip:</strong> Use the browser's DevTools Network tab to debug API calls and inspect responses." +
|
|
"</div>" +
|
|
|
|
"</div>" +
|
|
"</body>" +
|
|
"</html>";
|
|
}
|
|
|
|
private String buildGermanHelp() {
|
|
return "<!DOCTYPE html>" +
|
|
"<html lang=\"de\">" +
|
|
"<head>" +
|
|
"<meta charset=\"UTF-8\">" +
|
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" +
|
|
"<title>OPC UA API Dokumentation</title>" +
|
|
"<style>" +
|
|
":root{--bg:#fff;--text:#1c1c1e;--border:#e5e5ea;--code-bg:#f5f5f7;--blue:#007aff;--green:#34c759;--orange:#ff9500}" +
|
|
"@media(prefers-color-scheme:dark){:root{--bg:#000;--text:#fff;--border:#38383a;--code-bg:#1c1c1e}}" +
|
|
"*{margin:0;padding:0;box-sizing:border-box}" +
|
|
"body{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Text',Arial,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;padding:20px}" +
|
|
".container{max-width:1200px;margin:0 auto}" +
|
|
"header{border-bottom:2px solid var(--blue);padding-bottom:20px;margin-bottom:40px}" +
|
|
"h1{font-size:32px;font-weight:700;margin-bottom:10px}" +
|
|
".lang-switch{float:right}" +
|
|
".lang-switch a{color:var(--blue);text-decoration:none;margin:0 5px}" +
|
|
"h2{font-size:24px;font-weight:600;margin:30px 0 15px;color:var(--blue)}" +
|
|
"h3{font-size:18px;font-weight:600;margin:20px 0 10px}" +
|
|
".endpoint{background:var(--code-bg);padding:15px;border-radius:8px;margin:15px 0;border-left:4px solid var(--blue)}" +
|
|
".method{display:inline-block;padding:4px 8px;border-radius:4px;font-weight:600;font-size:12px;margin-right:10px}" +
|
|
".method.get{background:var(--green);color:#fff}" +
|
|
".method.post{background:var(--orange);color:#fff}" +
|
|
"pre{background:var(--code-bg);padding:15px;border-radius:8px;overflow-x:auto;margin:10px 0}" +
|
|
"code{font-family:'SF Mono',Monaco,'Courier New',monospace;font-size:14px}" +
|
|
".note{background:#fff3cd;border-left:4px solid var(--orange);padding:15px;margin:15px 0;border-radius:4px}" +
|
|
"table{width:100%;border-collapse:collapse;margin:15px 0}" +
|
|
"th,td{padding:12px;text-align:left;border-bottom:1px solid var(--border)}" +
|
|
"th{font-weight:600;background:var(--code-bg)}" +
|
|
".toc{background:var(--code-bg);padding:20px;border-radius:8px;margin:20px 0}" +
|
|
".toc ul{list-style:none;padding-left:0}" +
|
|
".toc li{margin:8px 0}" +
|
|
".toc a{color:var(--blue);text-decoration:none}" +
|
|
"</style>" +
|
|
"</head>" +
|
|
"<body>" +
|
|
"<div class=\"container\">" +
|
|
"<header>" +
|
|
"<div class=\"lang-switch\">" +
|
|
"<a href=\"?lang=en\">English</a> | <a href=\"?lang=de\">Deutsch</a>" +
|
|
"</div>" +
|
|
"<h1>🔧 OPC UA REST API Dokumentation</h1>" +
|
|
"<p>Vollständige Referenz zur Integration mit der OPC UA HTTP API</p>" +
|
|
"</header>" +
|
|
|
|
"<div class=\"toc\">" +
|
|
"<h2>Inhaltsverzeichnis</h2>" +
|
|
"<ul>" +
|
|
"<li><a href=\"#overview\">Übersicht</a></li>" +
|
|
"<li><a href=\"#authentication\">Authentifizierung</a></li>" +
|
|
"<li><a href=\"#endpoints\">API Endpunkte</a></li>" +
|
|
"<li><a href=\"#integration\">Drittsystem Integration</a></li>" +
|
|
"<li><a href=\"#examples\">Vollständige Beispiele</a></li>" +
|
|
"<li><a href=\"#errors\">Fehlerbehandlung</a></li>" +
|
|
"</ul>" +
|
|
"</div>" +
|
|
|
|
"<h2 id=\"overview\">Übersicht</h2>" +
|
|
"<p>Die OPC UA HTTP API bietet RESTful Zugriff auf OPC UA Server Daten. Alle Endpunkte akzeptieren und liefern JSON.</p>" +
|
|
"<p><strong>Basis-URL:</strong> <code>http://localhost:8081</code></p>" +
|
|
"<p><strong>Content-Type:</strong> <code>application/json</code></p>" +
|
|
|
|
"<h2 id=\"authentication\">Authentifizierung</h2>" +
|
|
"<p>Aktuell ist keine Authentifizierung für lokalen Zugriff erforderlich. Für Produktionsumgebungen verwenden Sie HTTPS mit Client-Zertifikaten.</p>" +
|
|
|
|
"<h2 id=\"endpoints\">API Endpunkte</h2>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method get\">GET</span> /api/status</h3>" +
|
|
"<p>OPC UA Verbindungsstatus abfragen</p>" +
|
|
"<h4>Antwort:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"connected\": true," +
|
|
" \"timestamp\": 1707989123456" +
|
|
"}</code></pre>" +
|
|
"<h4>Beispiel:</h4>" +
|
|
"<pre><code>const response = await fetch('/api/status');" +
|
|
"const data = await response.json();" +
|
|
"console.log('Verbunden:', data.connected);</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method post\">POST</span> /api/read</h3>" +
|
|
"<p>Wert von einem OPC UA Knoten lesen</p>" +
|
|
"<h4>Request Body:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"nodeId\": \"ns=2;s=Temperature\"" +
|
|
"}</code></pre>" +
|
|
"<h4>Antwort:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"success\": true," +
|
|
" \"value\": \"25.5\"," +
|
|
" \"timestamp\": 1707989123456" +
|
|
"}</code></pre>" +
|
|
"<h4>Beispiel:</h4>" +
|
|
"<pre><code>const response = await fetch('/api/read', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({nodeId: 'ns=2;s=Temperature'})" +
|
|
"});" +
|
|
"const data = await response.json();" +
|
|
"console.log('Temperatur:', data.value);</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<div class=\"endpoint\">" +
|
|
"<h3><span class=\"method post\">POST</span> /api/write</h3>" +
|
|
"<p>Wert zu einem OPC UA Knoten schreiben</p>" +
|
|
"<h4>Request Body:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"nodeId\": \"ns=2;s=SetPoint\"," +
|
|
" \"value\": \"30.0\"" +
|
|
"}</code></pre>" +
|
|
"<h4>Antwort:</h4>" +
|
|
"<pre><code>{" +
|
|
" \"success\": true," +
|
|
" \"written\": true" +
|
|
"}</code></pre>" +
|
|
"<h4>Beispiel:</h4>" +
|
|
"<pre><code>const response = await fetch('/api/write', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({" +
|
|
" nodeId: 'ns=2;s=SetPoint'," +
|
|
" value: '30.0'" +
|
|
" })" +
|
|
"});" +
|
|
"const data = await response.json();" +
|
|
"console.log('Schreiben erfolgreich:', data.written);</code></pre>" +
|
|
"</div>" +
|
|
|
|
"<h2 id=\"integration\">Drittsystem Integration</h2>" +
|
|
"<p>Verwenden Sie die API um OPC UA Daten mit externen Systemen zu integrieren.</p>" +
|
|
|
|
"<h3>Beispiel: Daten an externe REST API senden</h3>" +
|
|
"<pre><code>// Von OPC UA lesen" +
|
|
"const opcResponse = await fetch('/api/read', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({nodeId: 'ns=2;s=Temperature'})" +
|
|
"});" +
|
|
"const opcData = await opcResponse.json();" +
|
|
"\n" +
|
|
"// An externes System senden" +
|
|
"await fetch('https://api.example.com/data', {" +
|
|
" method: 'POST'," +
|
|
" headers: {" +
|
|
" 'Content-Type': 'application/json'," +
|
|
" 'Authorization': 'Bearer IHR_TOKEN'" +
|
|
" }," +
|
|
" body: JSON.stringify({" +
|
|
" sensor: 'temperatur'," +
|
|
" value: opcData.value," +
|
|
" timestamp: new Date().toISOString()" +
|
|
" })" +
|
|
"});</code></pre>" +
|
|
|
|
"<h3>Beispiel: Login Script mit Session Speicherung</h3>" +
|
|
"<pre><code>// Bei externem System anmelden" +
|
|
"const loginResponse = await fetch('https://api.example.com/auth/login', {" +
|
|
" method: 'POST'," +
|
|
" headers: {'Content-Type': 'application/json'}," +
|
|
" body: JSON.stringify({" +
|
|
" username: 'benutzer'," +
|
|
" password: 'geheim'" +
|
|
" })" +
|
|
"});" +
|
|
"const session = await loginResponse.json();" +
|
|
"\n" +
|
|
"// Session für spätere Verwendung speichern" +
|
|
"store.set('externeSession', session.token);" +
|
|
"store.set('externeAblauf', session.expiresAt);" +
|
|
"\n" +
|
|
"// In nachfolgenden Requests verwenden" +
|
|
"const token = store.get('externeSession');" +
|
|
"await fetch('https://api.example.com/data', {" +
|
|
" headers: {'Authorization': 'Bearer ' + token}" +
|
|
"});</code></pre>" +
|
|
|
|
"<h2 id=\"errors\">Fehlerbehandlung</h2>" +
|
|
"<h3>Fehler-Antwort Format:</h3>" +
|
|
"<pre><code>{" +
|
|
" \"success\": false," +
|
|
" \"error\": \"Fehlermeldung\"" +
|
|
"}</code></pre>" +
|
|
|
|
"<h3>Häufige Fehler:</h3>" +
|
|
"<table>" +
|
|
"<tr><th>Status</th><th>Fehler</th><th>Lösung</th></tr>" +
|
|
"<tr><td>503</td><td>OPC UA nicht verbunden</td><td>OPC UA Verbindung prüfen</td></tr>" +
|
|
"<tr><td>400</td><td>Ungültige nodeId</td><td>Node ID Format überprüfen</td></tr>" +
|
|
"<tr><td>500</td><td>Lesen/Schreiben fehlgeschlagen</td><td>Node Berechtigungen prüfen</td></tr>" +
|
|
"</table>" +
|
|
|
|
"<div class=\"note\">" +
|
|
"<strong>💡 Tipp:</strong> Verwenden Sie die Browser DevTools (Network Tab) um API Aufrufe zu debuggen und Antworten zu inspizieren." +
|
|
"</div>" +
|
|
|
|
"</div>" +
|
|
"</body>" +
|
|
"</html>";
|
|
}
|
|
}
|