Initial upload opcua service
This commit is contained in:
195
main/java/de/opcua/app/model/NodeAction.java
Normal file
195
main/java/de/opcua/app/model/NodeAction.java
Normal file
@@ -0,0 +1,195 @@
|
||||
package de.opcua.app.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents an action that can be executed when an OPC UA node value changes.
|
||||
* Supports trigger rules plus an optional JavaScript condition that is evaluated
|
||||
* with the selected/checked NodeIds before the main script is started.
|
||||
*/
|
||||
public class NodeAction {
|
||||
|
||||
public enum TriggerType {
|
||||
ON_CHANGE, // Execute on any value change
|
||||
ON_TRUE, // Execute when value becomes true/non-zero
|
||||
ON_FALSE, // Execute when value becomes false/zero
|
||||
ON_EVEN, // Execute when value is even
|
||||
ON_ODD, // Execute when value is odd
|
||||
ON_VALUE, // Execute when value equals specific value
|
||||
ON_GREATER_THAN, // Execute when value > threshold
|
||||
ON_LESS_THAN, // Execute when value < threshold
|
||||
ON_INTERVAL // Execute on timer interval
|
||||
}
|
||||
|
||||
private String nodeId;
|
||||
private String actionName;
|
||||
private TriggerType triggerType;
|
||||
private String script; // JavaScript code to execute
|
||||
private String triggerValue; // For ON_VALUE, ON_GREATER_THAN, ON_LESS_THAN
|
||||
private int intervalMs; // For ON_INTERVAL
|
||||
private boolean enabled;
|
||||
private String lastValue; // Track last value for change detection
|
||||
|
||||
// Extended scripting / checkbox condition support
|
||||
private boolean conditionEnabled;
|
||||
private String conditionScript;
|
||||
private List<String> conditionNodeIds;
|
||||
private Map<String, String> nodeAliases; // nodeId -> variable alias used in JavaScript
|
||||
|
||||
public NodeAction() {
|
||||
this.enabled = true;
|
||||
this.triggerType = TriggerType.ON_CHANGE;
|
||||
this.conditionEnabled = false;
|
||||
this.conditionScript = "";
|
||||
this.conditionNodeIds = new ArrayList<>();
|
||||
this.nodeAliases = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public NodeAction(String nodeId, String actionName, TriggerType triggerType, String script) {
|
||||
this();
|
||||
this.nodeId = nodeId;
|
||||
this.actionName = actionName;
|
||||
this.triggerType = triggerType;
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this action should be triggered based on the new value.
|
||||
* The optional JavaScript condition is evaluated later in ActionService,
|
||||
* because it may need fresh values from additional NodeIds.
|
||||
*/
|
||||
public boolean shouldTrigger(String newValue) {
|
||||
if (!enabled) return false;
|
||||
|
||||
try {
|
||||
switch (triggerType) {
|
||||
case ON_CHANGE:
|
||||
boolean changed = !Objects.equals(lastValue, newValue);
|
||||
lastValue = newValue;
|
||||
return changed;
|
||||
|
||||
case ON_TRUE:
|
||||
return isTruthyValue(newValue);
|
||||
|
||||
case ON_FALSE:
|
||||
return !isTruthyValue(newValue);
|
||||
|
||||
case ON_EVEN:
|
||||
return isEven(newValue);
|
||||
|
||||
case ON_ODD:
|
||||
return isOdd(newValue);
|
||||
|
||||
case ON_VALUE:
|
||||
return Objects.equals(newValue, triggerValue);
|
||||
|
||||
case ON_GREATER_THAN:
|
||||
return compareNumeric(newValue, triggerValue) > 0;
|
||||
|
||||
case ON_LESS_THAN:
|
||||
return compareNumeric(newValue, triggerValue) < 0;
|
||||
|
||||
case ON_INTERVAL:
|
||||
// Interval-based triggers are handled separately
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error checking trigger for action " + actionName + ": " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTruthyValue(String value) {
|
||||
if (value == null || value.trim().isEmpty()) return false;
|
||||
|
||||
if ("true".equalsIgnoreCase(value.trim())) return true;
|
||||
if ("false".equalsIgnoreCase(value.trim())) return false;
|
||||
|
||||
try {
|
||||
double num = Double.parseDouble(value.trim());
|
||||
return num != 0.0;
|
||||
} catch (NumberFormatException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEven(String value) {
|
||||
try {
|
||||
long num = Long.parseLong(value.trim());
|
||||
return num % 2 == 0;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOdd(String value) {
|
||||
try {
|
||||
long num = Long.parseLong(value.trim());
|
||||
return num % 2 != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int compareNumeric(String value1, String value2) {
|
||||
try {
|
||||
double num1 = Double.parseDouble(value1.trim());
|
||||
double num2 = Double.parseDouble(value2.trim());
|
||||
return Double.compare(num1, num2);
|
||||
} catch (NumberFormatException e) {
|
||||
return value1.compareTo(value2);
|
||||
}
|
||||
}
|
||||
|
||||
public String getNodeId() { return nodeId; }
|
||||
public void setNodeId(String nodeId) { this.nodeId = nodeId; }
|
||||
|
||||
public String getActionName() { return actionName; }
|
||||
public void setActionName(String actionName) { this.actionName = actionName; }
|
||||
|
||||
public TriggerType getTriggerType() { return triggerType; }
|
||||
public void setTriggerType(TriggerType triggerType) { this.triggerType = triggerType; }
|
||||
|
||||
public String getScript() { return script; }
|
||||
public void setScript(String script) { this.script = script; }
|
||||
|
||||
public String getTriggerValue() { return triggerValue; }
|
||||
public void setTriggerValue(String triggerValue) { this.triggerValue = triggerValue; }
|
||||
|
||||
public int getIntervalMs() { return intervalMs; }
|
||||
public void setIntervalMs(int intervalMs) { this.intervalMs = intervalMs; }
|
||||
|
||||
public boolean isEnabled() { return enabled; }
|
||||
public void setEnabled(boolean enabled) { this.enabled = enabled; }
|
||||
|
||||
public String getLastValue() { return lastValue; }
|
||||
public void setLastValue(String lastValue) { this.lastValue = lastValue; }
|
||||
|
||||
public boolean isConditionEnabled() { return conditionEnabled; }
|
||||
public void setConditionEnabled(boolean conditionEnabled) { this.conditionEnabled = conditionEnabled; }
|
||||
|
||||
public String getConditionScript() { return conditionScript; }
|
||||
public void setConditionScript(String conditionScript) { this.conditionScript = conditionScript; }
|
||||
|
||||
public List<String> getConditionNodeIds() { return conditionNodeIds; }
|
||||
public void setConditionNodeIds(List<String> conditionNodeIds) {
|
||||
this.conditionNodeIds = conditionNodeIds != null ? new ArrayList<>(conditionNodeIds) : new ArrayList<>();
|
||||
}
|
||||
|
||||
public Map<String, String> getNodeAliases() { return nodeAliases; }
|
||||
public void setNodeAliases(Map<String, String> nodeAliases) {
|
||||
this.nodeAliases = nodeAliases != null ? new LinkedHashMap<>(nodeAliases) : new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return actionName + " (" + triggerType + ")";
|
||||
}
|
||||
}
|
||||
75
main/java/de/opcua/app/model/NodeRow.java
Normal file
75
main/java/de/opcua/app/model/NodeRow.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package de.opcua.app.model;
|
||||
|
||||
import javafx.beans.property.*;
|
||||
|
||||
public class NodeRow {
|
||||
|
||||
private final BooleanProperty selected = new SimpleBooleanProperty(false);
|
||||
private final StringProperty displayName = new SimpleStringProperty("");
|
||||
private final StringProperty nodeType = new SimpleStringProperty("");
|
||||
private final StringProperty nodeId = new SimpleStringProperty("");
|
||||
private final StringProperty namespaceIndex = new SimpleStringProperty("");
|
||||
private final StringProperty identifierType = new SimpleStringProperty("");
|
||||
private final StringProperty value = new SimpleStringProperty("");
|
||||
|
||||
public NodeRow() {}
|
||||
|
||||
public NodeRow(
|
||||
boolean selected,
|
||||
String displayName,
|
||||
String nodeType,
|
||||
String nodeId,
|
||||
String namespaceIndex,
|
||||
String identifierType,
|
||||
String value
|
||||
) {
|
||||
this.selected.set(selected);
|
||||
this.displayName.set(displayName);
|
||||
this.nodeType.set(nodeType);
|
||||
this.nodeId.set(nodeId);
|
||||
this.namespaceIndex.set(namespaceIndex);
|
||||
this.identifierType.set(identifierType);
|
||||
this.value.set(value);
|
||||
}
|
||||
|
||||
// --- Properties ------------------------------------------------
|
||||
|
||||
public BooleanProperty selectedProperty() { return selected; }
|
||||
public StringProperty displayNameProperty() { return displayName; }
|
||||
public StringProperty nodeTypeProperty() { return nodeType; }
|
||||
public StringProperty nodeIdProperty() { return nodeId; }
|
||||
public StringProperty namespaceIndexProperty() { return namespaceIndex; }
|
||||
public StringProperty identifierTypeProperty() { return identifierType; }
|
||||
public StringProperty valueProperty() { return value; }
|
||||
|
||||
// --- Convenience ----------------------------------------------
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected.get();
|
||||
}
|
||||
|
||||
public void setSelected(boolean v) {
|
||||
selected.set(v);
|
||||
}
|
||||
|
||||
public String getNodeId() {
|
||||
return nodeId.get();
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName.get();
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value.get();
|
||||
}
|
||||
|
||||
public void setValue(String v) {
|
||||
value.set(v);
|
||||
}
|
||||
|
||||
/** 🔥 DAS IST DER FIX FÜR <err> */
|
||||
public boolean isReadable() {
|
||||
return "Variable".equalsIgnoreCase(nodeType.get());
|
||||
}
|
||||
}
|
||||
28
main/java/de/opcua/app/model/TreeNodeRef.java
Normal file
28
main/java/de/opcua/app/model/TreeNodeRef.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package de.opcua.app.model;
|
||||
|
||||
public record TreeNodeRef(
|
||||
String displayName,
|
||||
String nodeId,
|
||||
String browseName,
|
||||
String nodeClass,
|
||||
String dataType,
|
||||
String accessLevel,
|
||||
String referenceTypeId // ← NEU: z.B. "i=35", "i=46", "i=47"
|
||||
) {
|
||||
// Backward-compatible constructors
|
||||
public TreeNodeRef(String displayName, String nodeId) {
|
||||
this(displayName, nodeId, displayName, "Unknown", "Unknown", "ReadWrite", null);
|
||||
}
|
||||
|
||||
// Bestehender 6-Arg-Konstruktor bleibt kompatibel
|
||||
public TreeNodeRef(String displayName, String nodeId, String browseName,
|
||||
String nodeClass, String dataType, String accessLevel) {
|
||||
this(displayName, nodeId, browseName, nodeClass, dataType, accessLevel, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (displayName == null || displayName.isBlank()) return nodeId;
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user