Initial upload opcua simulator

This commit is contained in:
Christoph Hehl
2026-05-10 14:17:32 +02:00
commit 83052f99b6
37 changed files with 66609 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,8 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder><pattern>%d{HH:mm:ss.SSS} %-5level %logger{28} - %msg%n</pattern></encoder>
</appender>
<root level="INFO"><appender-ref ref="STDOUT"/></root>
<logger name="de.opcua.app" level="DEBUG"/>
<logger name="org.eclipse.milo" level="WARN"/>
</configuration>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="de.opcua.app.ui.SettingsDialog"
spacing="12" style="-fx-padding:16;">
<GridPane hgap="8" vgap="8">
<Label text="Port:" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<TextField fx:id="portField" GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<Label text="Endpoint-Pfad:" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<TextField fx:id="endpointPathField" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="App-Name:" GridPane.columnIndex="0" GridPane.rowIndex="2"/>
<TextField fx:id="applicationNameField" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label text="App-URI:" GridPane.columnIndex="0" GridPane.rowIndex="3"/>
<TextField fx:id="applicationUriField" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
<Label text="Update (s):" GridPane.columnIndex="0" GridPane.rowIndex="4"/>
<Spinner fx:id="updateIntervalSpinner" GridPane.columnIndex="1" GridPane.rowIndex="4"/>
<Label text="Noise (%):" GridPane.columnIndex="0" GridPane.rowIndex="5"/>
<Slider fx:id="noiseSlider" min="0" max="20" GridPane.columnIndex="1" GridPane.rowIndex="5"/>
<columnConstraints>
<ColumnConstraints minWidth="120"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="200"/>
</columnConstraints>
</GridPane>
<HBox spacing="8" alignment="CENTER_RIGHT">
<Button text="OK" onAction="#onOk" style="-fx-background-color:#4CAF50;-fx-text-fill:white;"/>
<Button text="Abbrechen" onAction="#onCancel"/>
</HBox>
</VBox>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<?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.SimulatorController">
<top>
<MenuBar>
<Menu text="Datei">
<MenuItem text="Export laden…" onAction="#onLoadExport"/>
<MenuItem text="Struktur speichern…" onAction="#onSaveStructure"/>
<SeparatorMenuItem/>
<MenuItem text="Einstellungen…" onAction="#onSettings"/>
<SeparatorMenuItem/>
<MenuItem text="Beenden" onAction="#onExit"/>
</Menu>
<Menu text="Server">
<MenuItem fx:id="startMenuItem" text="▶ Starten" onAction="#onStartServer"/>
<MenuItem fx:id="stopMenuItem" text="■ Stoppen" onAction="#onStopServer" disable="true"/>
</Menu>
<Menu text="Bearbeiten">
<MenuItem text="+ Rootelement" onAction="#onAddRootElement"/>
<MenuItem text="+ Ordner" onAction="#onAddFolder"/>
<MenuItem text="+ Variable" onAction="#onAddVariable"/>
<MenuItem text="Löschen" onAction="#onDeleteNode"/>
</Menu>
</MenuBar>
</top>
<bottom>
<HBox spacing="10" style="-fx-padding:3 8;-fx-background-color:#f0f0f0;-fx-border-color:#ccc;-fx-border-width:1 0 0 0;">
<Label fx:id="statusLabel" text="Bereit" HBox.hgrow="ALWAYS"/>
<Label fx:id="nodeCountLabel" text="Nodes: 0"/>
<Label fx:id="portLabel" text="Port: 4840"/>
<Label fx:id="serverStatusLabel" text="● Server: Gestoppt"
style="-fx-text-fill:#f44336;-fx-font-size:13px;"/>
</HBox>
</bottom>
<center>
<SplitPane dividerPositions="0.38">
<!-- Linke Seite: Baum -->
<VBox spacing="4" style="-fx-padding:8;">
<Label text="Adressraum" style="-fx-font-weight:bold;"/>
<TreeView fx:id="treeView" VBox.vgrow="ALWAYS"/>
<HBox spacing="4">
<Button text="+ Rootelement" onAction="#onAddRootElement"/>
<Button text="+ Ordner" onAction="#onAddFolder"/>
<Button text="+ Variable" onAction="#onAddVariable"/>
<Button text="🗑 Löschen" onAction="#onDeleteNode"/>
</HBox>
<HBox spacing="4">
<Button fx:id="startButton" text="▶ Start" onAction="#onStartServer"
style="-fx-background-color:#4CAF50;-fx-text-fill:white;"
maxWidth="Infinity" HBox.hgrow="ALWAYS"/>
<Button fx:id="stopButton" text="■ Stop" onAction="#onStopServer"
style="-fx-background-color:#f44336;-fx-text-fill:white;"
disable="true" maxWidth="Infinity" HBox.hgrow="ALWAYS"/>
</HBox>
</VBox>
<!-- Rechte Seite: Eigenschaften -->
<ScrollPane fitToWidth="true">
<VBox spacing="8" style="-fx-padding:8;">
<TitledPane text="Knoteneigenschaften" expanded="true" collapsible="false">
<GridPane hgap="8" vgap="4">
<Label text="NodeId:" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<TextField fx:id="nodeIdField" GridPane.columnIndex="1" GridPane.rowIndex="0" maxWidth="Infinity"/>
<Label text="DisplayName:" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<TextField fx:id="displayNameField" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="BrowseName:" GridPane.columnIndex="0" GridPane.rowIndex="2"/>
<TextField fx:id="browseNameField" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label text="NodeClass:" GridPane.columnIndex="0" GridPane.rowIndex="3"/>
<ComboBox fx:id="nodeClassCombo" GridPane.columnIndex="1" GridPane.rowIndex="3" maxWidth="Infinity"/>
<Label fx:id="dataTypeLabel" text="DataType:" GridPane.columnIndex="0" GridPane.rowIndex="4"/>
<ComboBox fx:id="dataTypeCombo" GridPane.columnIndex="1" GridPane.rowIndex="4" maxWidth="Infinity"/>
<Label fx:id="accessLevelLabel" text="AccessLevel:" GridPane.columnIndex="0" GridPane.rowIndex="5"/>
<ComboBox fx:id="accessLevelCombo" GridPane.columnIndex="1" GridPane.rowIndex="5" maxWidth="Infinity"/>
<Label fx:id="initialValueLabel" text="Wert:" GridPane.columnIndex="0" GridPane.rowIndex="6"/>
<TextField fx:id="initialValueField" GridPane.columnIndex="1" GridPane.rowIndex="6"/>
<columnConstraints>
<ColumnConstraints minWidth="90"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
</GridPane>
</TitledPane>
<HBox spacing="4">
<Button text="✔ Übernehmen" onAction="#onApplyChanges" HBox.hgrow="ALWAYS" maxWidth="Infinity"/>
<Button text="↩ Zurücksetzen" onAction="#onResetChanges" HBox.hgrow="ALWAYS" maxWidth="Infinity"/>
</HBox>
<!-- Live-Simulation (nur bei laufendem Server) -->
<VBox fx:id="simulationPanel" spacing="8" visible="false" managed="false">
<TitledPane text="Live-Wert setzen" expanded="true">
<GridPane hgap="8" vgap="4">
<Label text="Aktueller Wert:" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<TextField fx:id="currentValueField" editable="false" GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<Label text="Neuer Wert:" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<TextField fx:id="newValueField" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<columnConstraints>
<ColumnConstraints minWidth="90"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
</GridPane>
</TitledPane>
<Button text="Wert setzen" onAction="#onSetCurrentValue" maxWidth="Infinity"/>
</VBox>
</VBox>
</ScrollPane>
</SplitPane>
</center>
</BorderPane>