Skip to content
Snippets Groups Projects
Commit a6497e62 authored by Guillaume PICHON's avatar Guillaume PICHON
Browse files

Subscriber developpement progress.

parent 469c268b
No related branches found
No related tags found
No related merge requests found
......@@ -3,12 +3,13 @@ package fr.soleil.opcuaproxy;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.IdType;
import org.slf4j.Logger;
import org.tango.server.attribute.AttributeValue;
import org.tango.server.device.DeviceManager;
......@@ -17,11 +18,14 @@ import org.tango.server.events.EventType;
import fr.esrf.Tango.AttrQuality;
import fr.esrf.Tango.DevFailed;
import fr.soleil.opcuaproxy.attributes.IAttributeValueConsumer;
import fr.soleil.opcuaproxy.attributes.OpcUaAttribute;
import fr.soleil.opcuaproxy.attributes.OpcUaAttributeReference;
import fr.soleil.opcuaproxy.attributes.OpcUaSimpleNode;
import fr.soleil.opcuaproxy.connector.SubscriptionResult;
public abstract class AOpcUaSubscriber {
public abstract class AOpcUaSubscriber implements IAttributeValueConsumer {
protected static final double DEFAULT_SAMPLING_INTERVAL = 1000.0;
private Map<OpcUaAttributeReference, Set<OpcUaAttribute>> attributes = new TreeMap<>();
private Map<UInteger, Set<OpcUaAttribute>> attributesBySubscription = new TreeMap<>();
......@@ -100,7 +104,8 @@ public abstract class AOpcUaSubscriber {
}
}
public void attributeValueUpdate(Map<OpcUaAttributeReference, Object> values, Date date) {
@Override
public void onValueArrived(Map<OpcUaAttributeReference, Object> values, Date date) {
for (Entry<OpcUaAttributeReference, Object> valueEntry : values.entrySet()) {
OpcUaAttributeReference attrNode = valueEntry.getKey();
Object value = valueEntry.getValue();
......@@ -131,4 +136,69 @@ public abstract class AOpcUaSubscriber {
protected abstract DynamicManager getDynamicManager();
public OpcUaSimpleNode splitNamespaceTypeId(String value) {
return splitNamespaceTypeId(value, ",");
}
public OpcUaSimpleNode splitNamespaceTypeId(String value, String separator) {
int ns = getDefaultOpcUaNamespace();
IdType type = getDefaultOpcUaIdTypes();
String finalValue = value;
boolean valid = true;
if (value.contains(separator)) {
String[] resultSplt = value.split(separator);
if (resultSplt.length == 2) {
// Namespace only, default type
try {
ns = Integer.parseInt(resultSplt[0].trim());
finalValue = resultSplt[1].trim();
} catch (NumberFormatException e) {
valid = false;
getLogger().error("Invalid namespace. It must be an integer.", e);
}
} else { // >2
// Namespace and type
try {
ns = Integer.parseInt(resultSplt[0].trim());
String typeStr = resultSplt[1].trim();
IdType parsedType = stringToIdType(typeStr);
if (parsedType==null) {
valid = false;
getLogger().error("Invalid type. It must be either: " + IdType.Guid.name() + ", "
+ IdType.Numeric.name() + " or " + IdType.String.name());
}
else {
type = parsedType;
}
finalValue = resultSplt[2].trim();
} catch (NumberFormatException e) {
valid = false;
getLogger().error("Invalid namespace. It must be an integer.", e);
}
}
}
OpcUaSimpleNode node = null;
if (valid) {
node = new OpcUaSimpleNode(ns, type, finalValue);
}
return node;
}
protected abstract int getDefaultOpcUaNamespace();
protected abstract IdType getDefaultOpcUaIdTypes();
protected static IdType stringToIdType(String typeStr) {
String typeStrLow = typeStr.toLowerCase();
IdType type = null;
for (IdType idType : IdType.values()) {
if (idType != IdType.Opaque && idType.name().toLowerCase().equals(typeStrLow)) {
type = idType;
break;
}
}
return type;
}
}
......@@ -102,10 +102,10 @@ public class OpcUaProxy {
*/
public static void startNoDb() {
System.setProperty("OAPort", NO_DB_GIOP_PORT);
ServerManager.getInstance().addClass(OpcUaConnector.class.getCanonicalName(), OpcUaConnector.class);
ServerManager.getInstance().addClass(OpcUaSubscriber.class.getCanonicalName(), OpcUaSubscriber.class);
ServerManager.getInstance().addClass(OpcUaConnector.class.getSimpleName(), OpcUaConnector.class);
ServerManager.getInstance().addClass(OpcUaSubscriber.class.getSimpleName(), OpcUaSubscriber.class);
ServerManager.getInstance().start(new String[] { NO_DB_INSTANCE_NAME, "-nodb", "-dlist", NO_DB_DEVICE_NAME },
OpcUaProxy.class.getCanonicalName());
OpcUaProxy.class.getSimpleName());
}
/**
......@@ -115,12 +115,12 @@ public class OpcUaProxy {
*/
public static void startNoDbFile() throws DevFailed {
System.setProperty("OAPort", NO_DB_GIOP_PORT);
ServerManager.getInstance().addClass(OpcUaConnector.class.getCanonicalName(), OpcUaConnector.class);
ServerManager.getInstance().addClass(OpcUaSubscriber.class.getCanonicalName(), OpcUaSubscriber.class);
ServerManager.getInstance().addClass(OpcUaConnector.class.getSimpleName(), OpcUaConnector.class);
ServerManager.getInstance().addClass(OpcUaSubscriber.class.getSimpleName(), OpcUaSubscriber.class);
ServerManager.getInstance()
.start(new String[] { NO_DB_INSTANCE_NAME, "-nodb", "-dlist", NO_DB_DEVICE_NAME,
"-file=" + JTangoTest.class.getResource("/noDbproperties.txt").getPath() },
OpcUaProxy.class.getCanonicalName());
OpcUaProxy.class.getSimpleName());
}
}
......@@ -120,7 +120,7 @@ public class OpcUaAttributeParameters {
return new OpcUaSimpleNode(namespaceIdx, idType, id);
}
private static IdType nodeIdTypeToIdType(NodeIdType nodeIdType) {
public static IdType nodeIdTypeToIdType(NodeIdType nodeIdType) {
IdType idType = null;
if (nodeIdType != null) {
switch (nodeIdType) {
......@@ -140,6 +140,26 @@ public class OpcUaAttributeParameters {
return idType;
}
public static NodeIdType idTypeToNodeIdType(IdType idType) {
NodeIdType nodeIdType = null;
if (idType != null) {
switch (idType) {
case Guid:
nodeIdType = NodeIdType.GUID;
break;
case Numeric:
nodeIdType = NodeIdType.NUMERIC;
break;
case String:
nodeIdType = NodeIdType.STRING;
break;
default:
break;
}
}
return nodeIdType;
}
private static EventType attrDefEventToTangoEvent(Event attrEvent) {
EventType tangoEvent = null;
if (attrEvent != null) {
......
......@@ -11,6 +11,7 @@ import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.IdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tango.DeviceState;
......@@ -34,6 +35,7 @@ import org.tango.utils.DevFailedUtils;
import fr.esrf.Tango.DevFailed;
import fr.soleil.opcuaproxy.AOpcUaSubscriber;
import fr.soleil.opcuaproxy.OpcUaProxy;
import fr.soleil.opcuaproxy.attributes.IAttributeValueConsumer;
import fr.soleil.opcuaproxy.attributes.OpcUaAttribute;
import fr.soleil.opcuaproxy.attributes.OpcUaAttributeParameters;
import fr.soleil.opcuaproxy.attributes.OpcUaSimpleNode;
......@@ -53,6 +55,12 @@ public class OpcUaConnector extends AOpcUaSubscriber {
@DeviceProperty(defaultValue = "false", description = "Create diagnostics attributes")
private boolean createDiagnosticAttributes;
@DeviceProperty(defaultValue = "1", description = "OpcUa namespace index.")
private int defaultOpcUaNamespace;
@DeviceProperty(defaultValue = "String", description = "OpcUa id type. It must be either: Guid, Numeric or String.")
private String defaultOpcUaType;
@DeviceProperty(defaultValue = "1000.0", description = "OPCUA publishing interval in ms (double precision format 0.0ms)")
private double requestedPublishingIntervalForDiagnostic;
......@@ -201,7 +209,7 @@ public class OpcUaConnector extends AOpcUaSubscriber {
OpcUaSimpleNode sessionSimpleNodeId = new OpcUaSimpleNode(sessionNodeId);
SubscriptionResult result = createOPCUAAttributesByBrowsing(sessionSimpleNodeId, false,
requestedPublishingIntervalForDiagnostic, samplingIntervalForSubscriptionForDiagnostic,
Collections.emptySet());
Collections.emptySet(), this);
createTangoAttributes(result);
this.diagnosticAttributes = result;
}
......@@ -237,6 +245,26 @@ public class OpcUaConnector extends AOpcUaSubscriber {
}
}
/**
*
* @param argin
* @return
* @throws DevFailed
*/
@Command(name = "ReadNode", inTypeDesc = "Read the value of a given node", outTypeDesc = "The value.")
@StateMachine(deniedStates = { DeviceState.FAULT, DeviceState.RUNNING })
public String[] readNode(final String nodeToRead) throws DevFailed {
logger.info("Reading node {}", nodeToRead);
String identifierToRead = nodeToRead.trim();
OpcUaSimpleNode simpleNode = splitNamespaceTypeId(identifierToRead);
String[] result = { "Invalid node description." };
if (simpleNode != null) {
logger.info("Reading node ns={} id={}", simpleNode.getOpcuaNamespaceIndex(), simpleNode.getOpcuaIdStr());
result = opcUaProxyClient.readNode(simpleNode);
}
return result;
}
private void receivedAsyncReply(String[] reply) {
synchronized (asyncReplyResultAttribute) {
asyncReplyResultAttribute = reply;
......@@ -244,22 +272,22 @@ public class OpcUaConnector extends AOpcUaSubscriber {
}
public SubscriptionResult createOPCUAAttributes(List<OpcUaAttributeParameters> parametersList,
double requestedPublishingInterval) throws DevFailed {
double requestedPublishingInterval, IAttributeValueConsumer attributeValueConsumer) throws DevFailed {
SubscriptionResult result = null;
if (!parametersList.isEmpty()) {
result = this.opcUaProxyClient.subscribeTo(parametersList, requestedPublishingInterval,
this::attributeValueUpdate);
attributeValueConsumer);
}
return result;
}
public List<SubscriptionResult> createOPCUAAttributesByBrowsing(final List<OpcUaSimpleNode> nodesToBrowse,
boolean write, double requestedPublishingInterval, double samplingInterval, Set<EventType> activatedEvents)
boolean write, double requestedPublishingInterval, double samplingInterval, Set<EventType> activatedEvents, IAttributeValueConsumer attributeValueConsumer)
throws DevFailed {
List<SubscriptionResult> resultList = new ArrayList<>(nodesToBrowse.size());
for (OpcUaSimpleNode toBrowse : nodesToBrowse) {
SubscriptionResult browsedAttrResult = this.opcUaProxyClient.subscribeToLeafs(toBrowse, activatedEvents,
write, requestedPublishingInterval, samplingInterval, this::attributeValueUpdate);
write, requestedPublishingInterval, samplingInterval, attributeValueConsumer);
if (browsedAttrResult != null && browsedAttrResult.getSubscriptionId() != null) {
resultList.add(browsedAttrResult);
}
......@@ -273,10 +301,10 @@ public class OpcUaConnector extends AOpcUaSubscriber {
}
public SubscriptionResult createOPCUAAttributesByBrowsing(final OpcUaSimpleNode nodeToBrowse, boolean write,
double requestedPublishingInterval, double samplingInterval, Set<EventType> activatedEvents)
double requestedPublishingInterval, double samplingInterval, Set<EventType> activatedEvents, IAttributeValueConsumer attributeValueConsumer)
throws DevFailed {
SubscriptionResult result = this.opcUaProxyClient.subscribeToLeafs(nodeToBrowse, activatedEvents, write,
requestedPublishingInterval, samplingInterval, this::attributeValueUpdate);
requestedPublishingInterval, samplingInterval, attributeValueConsumer);
return result;
}
......@@ -396,4 +424,25 @@ public class OpcUaConnector extends AOpcUaSubscriber {
return logger;
}
@Override
public int getDefaultOpcUaNamespace() {
return defaultOpcUaNamespace;
}
@Override
protected IdType getDefaultOpcUaIdTypes() {
return stringToIdType(getDefaultOpcUaType());
}
public void setDefaultOpcUaNamespace(int defaultOpcUaNamespace) {
this.defaultOpcUaNamespace = defaultOpcUaNamespace;
}
public String getDefaultOpcUaType() {
return defaultOpcUaType;
}
public void setDefaultOpcUaType(String defaultOpcUaType) {
this.defaultOpcUaType = defaultOpcUaType;
}
}
......@@ -3,6 +3,7 @@ package fr.soleil.opcuaproxy.subscriber;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.milo.opcua.stack.core.types.enumerated.IdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tango.DeviceState;
......@@ -39,13 +40,16 @@ import fr.soleil.opcuaproxy.connector.SubscriptionResult;
public class OpcUaSubscriber extends AOpcUaSubscriber {
private static final Logger logger = LoggerFactory.getLogger(OpcUaSubscriber.class);
private static final int DEFAULT_NAMESPACE_INDEX = 1;
private static final NodeIdType DEFAULT_OPCUA_ID_TYPE = NodeIdType.STRING;
private static final double DEFAULT_SAMPLING_INTERVAL = 1000.0;
@DeviceProperty(defaultValue = "", description = "The device configuration in JSON format")
private String[] subscriptionsJson;
@DeviceProperty(defaultValue = "1", description = "OpcUa namespace index.")
private int defaultOpcUaNamespace;
@DeviceProperty(defaultValue = "String", description = "OpcUa id type. It must be either: Guid, Numeric or String.")
private String defaultOpcUaType;
/**
* Manage dynamic attributes and commands
*/
......@@ -104,30 +108,30 @@ public class OpcUaSubscriber extends AOpcUaSubscriber {
}
if (subscriptions != null) {
int defaultNamespaceIndex = DEFAULT_NAMESPACE_INDEX;
NodeIdType defaultOpcUaIdType = DEFAULT_OPCUA_ID_TYPE;
double defaultSamplingIndex = DEFAULT_SAMPLING_INTERVAL;
int defaultNamespaceIndexSub = getDefaultOpcUaNamespace();
NodeIdType defaultOpcUaIdTypeSub = OpcUaAttributeParameters.idTypeToNodeIdType(getDefaultOpcUaIdTypes());
double defaultSamplingIndexSub = DEFAULT_SAMPLING_INTERVAL;
if (subscriptions.getDefaultType() != null) {
defaultOpcUaIdType = subscriptions.getDefaultType();
defaultOpcUaIdTypeSub = subscriptions.getDefaultType();
}
if (subscriptions.getDefaultNamespaceIndex() != null) {
defaultNamespaceIndex = subscriptions.getDefaultNamespaceIndex();
defaultNamespaceIndexSub = subscriptions.getDefaultNamespaceIndex();
}
if (subscriptions.getDefaultSamplingInterval() != null) {
defaultSamplingIndex = subscriptions.getDefaultSamplingInterval();
defaultSamplingIndexSub = subscriptions.getDefaultSamplingInterval();
}
List<SubscriptionResult> subscriptionResults = new ArrayList<>(subscriptions.getSubscriptions().size());
for (Subscription subscription : subscriptions.getSubscriptions()) {
List<OpcUaAttributeParameters> parametersList = new ArrayList<>(subscription.getAttributes().size());
for (AttributeDefinition attrDef : subscription.getAttributes()) {
OpcUaAttributeParameters parameters = new OpcUaAttributeParameters(attrDef, defaultOpcUaIdType,
defaultNamespaceIndex, defaultSamplingIndex);
OpcUaAttributeParameters parameters = new OpcUaAttributeParameters(attrDef, defaultOpcUaIdTypeSub,
defaultNamespaceIndexSub, defaultSamplingIndexSub);
parametersList.add(parameters);
}
SubscriptionResult subscriptionResult = connector.createOPCUAAttributes(parametersList,
subscription.getRequestedPublishingInterval());
subscription.getRequestedPublishingInterval(), this);
subscriptionResults.add(subscriptionResult);
}
createTangoAttributes(subscriptionResults);
......@@ -193,4 +197,25 @@ public class OpcUaSubscriber extends AOpcUaSubscriber {
this.status = status;
}
@Override
public int getDefaultOpcUaNamespace() {
return defaultOpcUaNamespace;
}
@Override
protected IdType getDefaultOpcUaIdTypes() {
return stringToIdType(getDefaultOpcUaType());
}
public void setDefaultOpcUaNamespace(int defaultOpcUaNamespace) {
this.defaultOpcUaNamespace = defaultOpcUaNamespace;
}
public String getDefaultOpcUaType() {
return defaultOpcUaType;
}
public void setDefaultOpcUaType(String defaultOpcUaType) {
this.defaultOpcUaType = defaultOpcUaType;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment