Initial upload opcua service

This commit is contained in:
Christoph Hehl
2026-05-11 19:40:18 +02:00
commit abcd027897
207 changed files with 18613 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="de.opcua.app.ui.ConfigController"
prefWidth="980" prefHeight="760">
<top>
<Label text="Configuration" style="-fx-font-size:22px;-fx-font-weight:bold;" BorderPane.alignment="CENTER_LEFT">
<padding><Insets top="14" right="18" bottom="8" left="18"/></padding>
</Label>
</top>
<center>
<ScrollPane fitToWidth="true">
<VBox spacing="16">
<padding><Insets top="18" right="18" bottom="18" left="18"/></padding>
<TitledPane text="OPC UA Server" expanded="true">
<GridPane hgap="12" vgap="10">
<padding><Insets top="14" right="14" bottom="14" left="14"/></padding>
<columnConstraints>
<ColumnConstraints minWidth="170" halignment="RIGHT"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<Label text="Endpoint" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
<TextField fx:id="endpointTextBox" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
<Label text="Host" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<TextField fx:id="hostTextBox" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
</GridPane>
</TitledPane>
<TitledPane text="HTTP / HTTPS" expanded="true">
<GridPane hgap="12" vgap="10">
<padding><Insets top="14" right="14" bottom="14" left="14"/></padding>
<columnConstraints>
<ColumnConstraints minWidth="170" halignment="RIGHT"/>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints minWidth="110"/>
</columnConstraints>
<CheckBox fx:id="httpEnabledCheckBox" text="Enable HTTP" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
<Label text="HTTP Port" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<TextField fx:id="httpPortTextBox" GridPane.rowIndex="1" GridPane.columnIndex="1" maxWidth="140"/>
<Label text="z. B. 8081" GridPane.rowIndex="1" GridPane.columnIndex="2" style="-fx-text-fill:#888;"/>
<CheckBox fx:id="httpsEnabledCheckBox" text="Enable HTTPS" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<Label text="HTTPS Port" GridPane.rowIndex="3" GridPane.columnIndex="0"/>
<TextField fx:id="httpsPortTextBox" GridPane.rowIndex="3" GridPane.columnIndex="1" maxWidth="140"/>
<Label text="z. B. 8443" GridPane.rowIndex="3" GridPane.columnIndex="2" style="-fx-text-fill:#888;"/>
<Label text="Keystore" GridPane.rowIndex="4" GridPane.columnIndex="0"/>
<HBox spacing="8" GridPane.rowIndex="4" GridPane.columnIndex="1" GridPane.columnSpan="2">
<TextField fx:id="keystorePathTextBox" HBox.hgrow="ALWAYS"/>
<Button text="Browse..." onAction="#BrowseKeystore_Click"/>
</HBox>
<Label text="Keystore Password" GridPane.rowIndex="5" GridPane.columnIndex="0"/>
<PasswordField fx:id="keystorePasswordTextBox" GridPane.rowIndex="5" GridPane.columnIndex="1"/>
<Label text="Keystore Type" GridPane.rowIndex="6" GridPane.columnIndex="0"/>
<ComboBox fx:id="keystoreTypeComboBox" GridPane.rowIndex="6" GridPane.columnIndex="1" maxWidth="160"/>
</GridPane>
</TitledPane>
<TitledPane text="Portable Config / Verschluesselung / REST Auth" expanded="true">
<GridPane hgap="12" vgap="10">
<padding><Insets top="14" right="14" bottom="14" left="14"/></padding>
<columnConstraints>
<ColumnConstraints minWidth="190" halignment="RIGHT"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<Label text="Config-Verzeichnis" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
<Label fx:id="configDirectoryLabel" GridPane.rowIndex="0" GridPane.columnIndex="1" style="-fx-text-fill:#666;-fx-font-family:monospace;" wrapText="true"/>
<Label text="Settings-Datei" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<Label fx:id="settingsPathLabel" GridPane.rowIndex="1" GridPane.columnIndex="1" style="-fx-text-fill:#666;-fx-font-family:monospace;" wrapText="true"/>
<CheckBox fx:id="configEncryptionEnabledCheckBox" text="Config-Dateien verschluesseln (Actions, Templates, System Init)" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<Label text="Config-Passwort" GridPane.rowIndex="3" GridPane.columnIndex="0"/>
<PasswordField fx:id="configEncryptionPasswordField" GridPane.rowIndex="3" GridPane.columnIndex="1" promptText="Passwort fuer AES-GCM Verschluesselung"/>
<CheckBox fx:id="restAuthEnabledCheckBox" text="REST-API Authentifizierung aktivieren" GridPane.rowIndex="4" GridPane.columnIndex="1"/>
<Label text="REST Benutzer" GridPane.rowIndex="5" GridPane.columnIndex="0"/>
<TextField fx:id="restAuthUserTextBox" GridPane.rowIndex="5" GridPane.columnIndex="1" promptText="admin"/>
<Label text="REST Passwort" GridPane.rowIndex="6" GridPane.columnIndex="0"/>
<PasswordField fx:id="restAuthPasswordField" GridPane.rowIndex="6" GridPane.columnIndex="1" promptText="Leer lassen = bestehendes Passwort behalten"/>
<Label text="Hinweis" GridPane.rowIndex="7" GridPane.columnIndex="0"/>
<Label text="Nach Aktivierung der REST-Authentifizierung muessen REST-Clients Basic Auth verwenden. Die Web-Oberflaeche fragt das Passwort automatisch ab." GridPane.rowIndex="7" GridPane.columnIndex="1" wrapText="true" style="-fx-text-fill:#666;"/>
</GridPane>
</TitledPane>
<TitledPane text="System Init / RegLogin" expanded="true">
<VBox spacing="10">
<padding><Insets top="14" right="14" bottom="14" left="14"/></padding>
<Label text="Dieses globale Initial-Script wird dauerhaft gespeichert und beim Start/Connect geladen. Im Service-Modus laeuft es nach erfolgreichem OPC-Connect/Reconnect, wenn 'Nach OPC Connect' aktiv ist." wrapText="true"/>
<Label fx:id="systemInitPathLabel" style="-fx-text-fill:#666;-fx-font-family:monospace;"/>
<HBox spacing="18">
<CheckBox fx:id="systemInitEnabledCheckBox" text="Aktiv"/>
<CheckBox fx:id="systemInitRunAtProgramStartCheckBox" text="Bei Programmstart"/>
<CheckBox fx:id="systemInitRunAfterConnectCheckBox" text="Nach OPC Connect/Reconnect" selected="true"/>
</HBox>
<HBox spacing="8">
<Button text="RegLogin Template einfuegen" onAction="#InsertRegLoginTemplate_Click"/>
<Button text="Speichern &amp; jetzt ausfuehren" onAction="#RunSystemInit_Click"/>
</HBox>
<StackPane fx:id="systemInitEditorHost" minHeight="280" VBox.vgrow="ALWAYS"/>
</VBox>
</TitledPane>
<TitledPane text="Script Templates / Button-Vorlagen" expanded="false">
<VBox spacing="10">
<padding><Insets top="14" right="14" bottom="14" left="14"/></padding>
<Label text="Hier werden GET/POST/SET und eigene Templates gepflegt. Fuer jedes aktivierte Template erscheint im Create-New-Action-Dialog automatisch ein Button. Platzhalter werden beim Einfuegen durch feste NodeId-Codezeilen ersetzt." wrapText="true"/>
<Label fx:id="templatePathLabel" style="-fx-text-fill:#666;-fx-font-family:monospace;"/>
<SplitPane dividerPositions="0.30" minHeight="360" VBox.vgrow="ALWAYS">
<items>
<VBox spacing="8">
<ListView fx:id="templateListView" minWidth="220" VBox.vgrow="ALWAYS"/>
<HBox spacing="8">
<Button text="Neu" onAction="#NewTemplate_Click"/>
<Button text="Loeschen" onAction="#DeleteTemplate_Click"/>
</HBox>
</VBox>
<VBox spacing="8">
<GridPane hgap="10" vgap="8">
<columnConstraints>
<ColumnConstraints minWidth="90" halignment="RIGHT"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<Label text="Name" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
<TextField fx:id="templateNameField" GridPane.rowIndex="0" GridPane.columnIndex="1" promptText="z. B. POST an MES"/>
<Label text="Status" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<CheckBox fx:id="templateEnabledCheckBox" text="Aktiv / Button anzeigen" selected="true" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
</GridPane>
<HBox spacing="8">
<Button text="Platzhalter einfuegen" onAction="#InsertTemplatePlaceholders_Click"/>
<Button text="Templates speichern" onAction="#SaveTemplates_Click"/>
<Button text="Standard GET/POST/SET wiederherstellen" onAction="#ResetTemplates_Click"/>
</HBox>
<Label text="JavaScript Template" style="-fx-font-weight:bold;"/>
<StackPane fx:id="templateEditorHost" minHeight="260" VBox.vgrow="ALWAYS"/>
<Label text="Platzhalter: {{readNumberVars}}, {{readTextVars}}, {{payloadFields}}, {{opcWritesFromResult}}, {{selectedNodesComment}}, {{firstNodeIdJs}}, {{firstAlias}}" wrapText="true" style="-fx-text-fill:#666;"/>
</VBox>
</items>
</SplitPane>
</VBox>
</TitledPane>
</VBox>
</ScrollPane>
</center>
<bottom>
<HBox spacing="10" alignment="CENTER_RIGHT">
<padding><Insets top="14" right="14" bottom="14" left="14"/></padding>
<Button text="Save" prefWidth="110" onAction="#SaveButton_Click" style="-fx-background-color:#007aff;-fx-text-fill:white;-fx-font-weight:bold;"/>
<Button text="Cancel" prefWidth="110" onAction="#CancelButton_Click" style="-fx-background-color:#8e8e93;-fx-text-fill:white;"/>
</HBox>
</bottom>
</BorderPane>

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns:fx="http://javafx.com/fxml"
fx:controller="de.opcua.app.ui.MainController"
prefWidth="1262" prefHeight="619"
minWidth="900" minHeight="520"
stylesheets="@../styles/application.css">
<top>
<HBox spacing="8" alignment="CENTER_LEFT" styleClass="top-bar">
<padding>
<Insets top="10" right="12" bottom="10" left="12"/>
</padding>
<ImageView fitWidth="28" fitHeight="28" preserveRatio="true" smooth="true">
<image>
<Image url="@../styles/opcua-client-logo.png"/>
</image>
</ImageView>
<Label text="OPC UA Client" styleClass="app-title"/>
<Region HBox.hgrow="ALWAYS"/>
<Button fx:id="connectButton" text="Connect" minWidth="92" onAction="#connectButton_Click" styleClass="button-primary"/>
<Button fx:id="saveButton" text="Save" minWidth="80" onAction="#onSave"/>
<Button fx:id="settingsButton" text="Settings" minWidth="92" onAction="#onSettings"/>
</HBox>
</top>
<center>
<SplitPane dividerPositions="0.25" BorderPane.alignment="CENTER">
<items>
<VBox spacing="8" minWidth="240">
<padding>
<Insets top="10" right="6" bottom="10" left="10"/>
</padding>
<Label text="OPC UA Tree" styleClass="label-header"/>
<TreeView fx:id="myTreeView" VBox.vgrow="ALWAYS" minWidth="220"
onMouseClicked="#myTreeView_AfterSelect"/>
</VBox>
<VBox spacing="8" minWidth="520">
<padding>
<Insets top="10" right="10" bottom="10" left="6"/>
</padding>
<TableView fx:id="nodeListview" VBox.vgrow="ALWAYS" minHeight="260">
<columns>
<TableColumn fx:id="checkBoxColumn" text="Select" prefWidth="70"/>
<TableColumn fx:id="colDisplayName" text="DisplayName" prefWidth="160"/>
<TableColumn fx:id="colNodeType" text="NodeType" prefWidth="110"/>
<TableColumn fx:id="colNodeId" text="NodeId" prefWidth="280"/>
<TableColumn fx:id="colNamespaceIndex" text="NamespaceIndex" prefWidth="120"/>
<TableColumn fx:id="colIdentifierType" text="IdentifierType" prefWidth="120"/>
<TableColumn fx:id="colValue" text="Value" prefWidth="150"/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
<HBox spacing="8" alignment="CENTER_LEFT" styleClass="script-bar">
<Label text="JS:"/>
<TextField fx:id="scriptField" HBox.hgrow="ALWAYS" promptText="opc.read(&quot;ns=...&quot;)"/>
<Button fx:id="runScriptButton" text="Run" minWidth="70" onAction="#runScript"/>
</HBox>
<TextArea fx:id="logArea" visible="false" managed="false" prefRowCount="0"/>
</VBox>
</items>
</SplitPane>
</center>
</BorderPane>