196 lines
7.0 KiB
Java
196 lines
7.0 KiB
Java
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 + ")";
|
|
}
|
|
}
|