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

Debugging subscriptions by properties and updating the README

parent ae32b5b8
Branches
No related tags found
No related merge requests found
...@@ -64,17 +64,6 @@ Le device ne dispose pas de commandes en dehors des commandes usuelles de Tango. ...@@ -64,17 +64,6 @@ Le device ne dispose pas de commandes en dehors des commandes usuelles de Tango.
Un ensemble de propriété au nommage dynamique peut être utilisées pour décrire les souscriptions par les propriétés uniquement. [Voir paragraphe dédié.](#description-des-souscriptions-par-les-propriétés-uniquement) Un ensemble de propriété au nommage dynamique peut être utilisées pour décrire les souscriptions par les propriétés uniquement. [Voir paragraphe dédié.](#description-des-souscriptions-par-les-propriétés-uniquement)
# Description d'un nœud
Un nœud peut être décrit par trois paramètres :
* L'identifiant,
* Le NamespaceIndex,
* Le type d'identifiant.
Un namespaceIndex et un type d'identifiant par défaut sont définit par les propriétés. Il est possible de définir un nœud de trois manières :
* Identifiant seul : le namespaceIndex et le type d'identifiant par défaut sont utilisés
* NamespaceIndex, Identifiant : le type d'identifiant par défaut est utilisés
* NamespaceIndex, Type d'identifiant, Identifiant : La description est complète.
# Evenements # Evenements
Le device TangoOPCUA reçoit des évenements pour chaque changement de valeur d'un attribut OPCUA. En utilisant les propriété du device, il est possible de générer les évenements Tango équivalent. Le device TangoOPCUA reçoit des évenements pour chaque changement de valeur d'un attribut OPCUA. En utilisant les propriété du device, il est possible de générer les évenements Tango équivalent.
...@@ -181,22 +170,60 @@ Dans les propriétés `IdentifiersSubscription`, les attributs doivent être dé ...@@ -181,22 +170,60 @@ Dans les propriétés `IdentifiersSubscription`, les attributs doivent être dé
* Le nœud OPC-UA auquel souscrire pour la lecture * Le nœud OPC-UA auquel souscrire pour la lecture
* Obligatoire * Obligatoire
* L'interval d'échantillonnage * L'interval d'échantillonnage
* Il peut-être vide, la valeur par défaut sera utilisée. * Il peut-être vide, la valeur par défaut du device sera utilisée.
* Un booléen indiquant s'il faut i le nœud doit * Un booléen indiquant s'il faut i le nœud doit
* Il peut-être vide, il est à faux par défaut. * Il peut-être vide, il est à faux par défaut.
* Si le nœud est parcouru, un booléen indique * Si le nœud est parcouru, un booléen indique
* Il peut-être vide, il est à faux par défaut. Il n'est pas pris en compte si le précédent est à faux. * Il peut-être vide, il est à faux par défaut. Il n'est pas pris en compte si le précédent est à faux.
* Les nœuds ou écrire, séparés par le caractère `;` * Les nœuds ou écrire, séparés par le caractère `;`
## Nœuds OPC-UA
Les nœuds OPC-UA doivent être décrits avec les attributs suivant :
* Id : Identifiant OPC-UA. Sous forme d'une chaine de caractère, entre `"`, même s'il est numérique. Par exemple : `"1138"`.
* type : Type d'identifiant OPC-UA. Les valeurs possibles sont : String, Numeric et Guid.
* NamspaceIndex : Index du namespace du nœud.
Un namespaceIndex et un type d'identifiant par défaut sont définit par les propriété. Il est possible de définir un nœud de trois manières :
* Identifiant seul : le namespaceIndex et le type d'identifiant par défaut sont utilisés
* `"DBOPCUA"."Reel"`
* NamespaceIndex, Identifiant : le type d'identifiant par défaut est utilisés
* `2,"DBOPCUA"."Reel"`
* NamespaceIndex, Type d'identifiant, Identifiant : La description est complète.
* `2,string,"DBOPCUA"."Reel"`
## Exemple ## Exemple
| Property | Value | | Property | Value |
|:-----------------------------------------------|:----------------------------| |:-----------------------------------------------|:----------------------------|
| `IdentifiersSubscriptionAlpha` | `reel;;;"DBOPCUA"."Reel";;`<br/>`Att_Bool_Elec_1;;archive;/Application/SOLEIL/Batiment_T7/RDC/Elec/T7ELEC1.Value_Bool;1000.0;false;false;/Application/SOLEIL/Batiment_T7/RDC/Elec/T7ELEC1.Value_Bool;` | | `IdentifiersSubscriptionAlpha` | `reel;;;"DBOPCUA"."Reel";;;`<br/>`Att_Bool_Elec_1;;archive;/Application/SOLEIL/Batiment_T7/RDC/Elec/T7ELEC1.Value_Bool;1000.0;false;false;/Application/SOLEIL/Batiment_T7/RDC/Elec/T7ELEC1.Value_Bool;` |
| `SubscriptionDefaultSamplingIntervalAlpha` | 200.0 | | `SubscriptionDefaultSamplingIntervalAlpha` | 200.0 |
| `SubscriptionRequestedPublishingIntervalAlpha` | 1500 | | `SubscriptionRequestedPublishingIntervalAlpha` | 1500 |
| `SubscriptionDefaultOpcUaNamespaceAlpha` | 1 | | `SubscriptionDefaultOpcUaNamespaceAlpha` | 1 |
| `SubscriptionDefaultOpcUaTypeAlpha` | String | | `SubscriptionDefaultOpcUaTypeAlpha` | String |
Dans l'exemple ci-dessus une souscription est définie.
* L'interval de publication sera de 1500ms
* Elle comporte 2 attributs tango :
* `reel`
* Pas de label Tango
* Le nœud OPCUA pour la partie en lecture de l'attribut tango sera :
* Namespace=1 : valeur par défaut de la souscription
* Identifiant du nœud : `"DBOPCUA"."Reel"`
* Type d'ID=String : valeur par défaut de la souscription
* Pas d'évenements générés
* Inteval d'échantillonnage=200.0ms : valeur par défaut de la souscription
* L'attribut tango sera en lecture seule
* Le nœud OPC-UA ne sera pas parcouru et ne générera qu'un seul attribut tango
* `Att_Bool_Elec_1`
* Le nœud OPCUA pour la partie en lecture de l'attribut tango sera :
* Namespace=1 : valeur par défaut de la souscription
* Identifiant du nœud : `/Application/SOLEIL/Batiment_T7/RDC/Elec/T7ELEC1.Value_Bool`
* Type d'ID=String : valeur par défaut de la souscription
* Des évènements de type `archive` seront générés
* Inteval d'échantillonnage=1000.0ms
* L'attribut tango sera en lecture et écriture. Il écrira sur le même nœud que pour la lecture.
* Le nœud OPC-UA ne sera pas parcouru et ne générera qu'un seul attribut tango
# Déploiement # Déploiement
## Script d’exécution et librairies ## Script d’exécution et librairies
Le device utilise les librairies eclipse Milo et Jackson. Actuellement, ces dépendances ne sont pas présentes dans les déploiements. Il faut les rajouter ainsi que les dépendances liées. Le device utilise les librairies eclipse Milo et Jackson. Actuellement, ces dépendances ne sont pas présentes dans les déploiements. Il faut les rajouter ainsi que les dépendances liées.
......
...@@ -18,7 +18,15 @@ public class OpcUaAttributeParser { ...@@ -18,7 +18,15 @@ public class OpcUaAttributeParser {
private static final Logger logger = LoggerFactory.getLogger(OpcUaAttributeParser.class); private static final Logger logger = LoggerFactory.getLogger(OpcUaAttributeParser.class);
private static final String SEPARATOR = ";"; private static final String SEPARATOR = ";";
private static final String SUB_SEPARATOR = ","; private static final String SUB_SEPARATOR = ",";
private static final int NB_ELEMS_BEFORE_WRITE = 7;
private static final int ATTR_NAME_IDX = 0;
private static final int ATTR_LABEL_IDX = 1;
private static final int ATTR_EVENTS_IDX = 2;
private static final int OPCUA_READ_IDX = 3;
private static final int OPCUA_SMPL_INT_IDX = 4;
private static final int OPCUA_BRWS_IDX = 5;
private static final int OPCUA_WLEAF_IDX = 6;
private static final int OPCUA_WRITE_IDX = 7;
private int defaultOpcuaNamespace; private int defaultOpcuaNamespace;
private IdType defaultOpcuaIdTypes; private IdType defaultOpcuaIdTypes;
...@@ -50,17 +58,13 @@ public class OpcUaAttributeParser { ...@@ -50,17 +58,13 @@ public class OpcUaAttributeParser {
for (String inputProperty : inputProperties) { for (String inputProperty : inputProperties) {
String attrDef = inputProperty.trim(); String attrDef = inputProperty.trim();
String[] elems = attrDef.split(SEPARATOR); String[] elems = attrDef.split(SEPARATOR);
if (elems.length >= NB_ELEMS_BEFORE_WRITE) { if (elems.length >= OPCUA_READ_IDX + 1) {
String name = elems[0].trim(); String name = elems[ATTR_NAME_IDX].trim();
if (name.length() == 0) { if (name.length() == 0) {
throw DevFailedUtils.newDevFailed("Attribute name error", "Attribute name cannot be empty."); throw DevFailedUtils.newDevFailed("Attribute name error", "Attribute name cannot be empty.");
} }
String label = elems[1].trim(); String label = elems[ATTR_LABEL_IDX].trim();
String eventsPart = elems[2].trim(); String eventsPart = elems[ATTR_EVENTS_IDX].trim();
String readPart = elems[3].trim();
String samplingIntervalStr = elems[4].trim();
String toBrowseStr = elems[5].trim().toLowerCase();
String toWriteLeafsStr = elems[6].trim().toLowerCase();
double samplingInterval = defaultSamplingInterval; double samplingInterval = defaultSamplingInterval;
boolean toBrowse = false; boolean toBrowse = false;
boolean toWriteLeafs = false; boolean toWriteLeafs = false;
...@@ -71,6 +75,11 @@ public class OpcUaAttributeParser { ...@@ -71,6 +75,11 @@ public class OpcUaAttributeParser {
activatedEvents.add(EventType.getEvent(eventName.toLowerCase().trim())); activatedEvents.add(EventType.getEvent(eventName.toLowerCase().trim()));
} }
} }
String readPart = elems[OPCUA_READ_IDX].trim();
List<OpcUaAttributeReference> writeParts = Collections.emptyList();
if (elems.length >= OPCUA_SMPL_INT_IDX + 1) {
String samplingIntervalStr = elems[OPCUA_SMPL_INT_IDX].trim();
if (samplingIntervalStr.length() > 0) { if (samplingIntervalStr.length() > 0) {
try { try {
samplingInterval = Double.parseDouble(samplingIntervalStr); samplingInterval = Double.parseDouble(samplingIntervalStr);
...@@ -82,15 +91,23 @@ public class OpcUaAttributeParser { ...@@ -82,15 +91,23 @@ public class OpcUaAttributeParser {
throw DevFailedUtils.newDevFailed(errorTtl, errorMsg); throw DevFailedUtils.newDevFailed(errorTtl, errorMsg);
} }
} }
}
if (elems.length >= OPCUA_BRWS_IDX + 1) {
String toBrowseStr = elems[OPCUA_BRWS_IDX].trim().toLowerCase();
if (toBrowseStr.length() > 0) { if (toBrowseStr.length() > 0) {
toBrowse = Boolean.parseBoolean(toBrowseStr); toBrowse = Boolean.parseBoolean(toBrowseStr);
} }
}
if (elems.length >= OPCUA_WLEAF_IDX + 1) {
String toWriteLeafsStr = elems[OPCUA_WLEAF_IDX].trim().toLowerCase();
if (toWriteLeafsStr.length() > 0) { if (toWriteLeafsStr.length() > 0) {
toWriteLeafs = Boolean.parseBoolean(toWriteLeafsStr); toWriteLeafs = Boolean.parseBoolean(toWriteLeafsStr);
} }
}
List<OpcUaAttributeReference> writeParts = Collections.emptyList(); int nbWriteParts = elems.length - OPCUA_WRITE_IDX;
int nbWriteParts = elems.length - NB_ELEMS_BEFORE_WRITE;
if (nbWriteParts > 0) { if (nbWriteParts > 0) {
writeParts = new ArrayList<>(nbWriteParts); writeParts = new ArrayList<>(nbWriteParts);
for (int i = 0; i < nbWriteParts; i++) { for (int i = 0; i < nbWriteParts; i++) {
...@@ -102,14 +119,14 @@ public class OpcUaAttributeParser { ...@@ -102,14 +119,14 @@ public class OpcUaAttributeParser {
OpcUaAttributeReference writeRef = new OpcUaAttributeReference(writeNode); OpcUaAttributeReference writeRef = new OpcUaAttributeReference(writeNode);
writeParts.add(writeRef); writeParts.add(writeRef);
} else { } else {
throw DevFailedUtils.newDevFailed("Invalid node description in write part for attribute " + name, throw DevFailedUtils.newDevFailed(
"Invalid node description in write part for attribute " + name,
"The following node description is invalid: " + writePart "The following node description is invalid: " + writePart
+ "\nCheck the logs for more information."); + "\nCheck the logs for more information.");
} }
} }
} }
} }
if (name.length() > 0 && readPart.length() > 0) { if (name.length() > 0 && readPart.length() > 0) {
OpcUaSimpleNode readNode = splitNamespaceTypeId(readPart); OpcUaSimpleNode readNode = splitNamespaceTypeId(readPart);
if (readNode != null) { if (readNode != null) {
...@@ -128,6 +145,11 @@ public class OpcUaAttributeParser { ...@@ -128,6 +145,11 @@ public class OpcUaAttributeParser {
return parameters; return parameters;
} }
/**
*
* @param value The OpcUa node description : ns,IdType,id
* @return
*/
public OpcUaSimpleNode splitNamespaceTypeId(String value) { public OpcUaSimpleNode splitNamespaceTypeId(String value) {
return splitNamespaceTypeId(value, ","); return splitNamespaceTypeId(value, ",");
} }
......
...@@ -260,7 +260,11 @@ public class OpcUaSubscriber extends AOpcUaSubscriber { ...@@ -260,7 +260,11 @@ public class OpcUaSubscriber extends AOpcUaSubscriber {
SubscriptionResult subscriptionResult = connector.createOPCUAAttributes(parametersList, SubscriptionResult subscriptionResult = connector.createOPCUAAttributes(parametersList,
requestedPublishingInterval, this); requestedPublishingInterval, this);
if (subscriptionResult != null && subscriptionResult.getAttributes()!=null) {
subscriptionResults.add(subscriptionResult); subscriptionResults.add(subscriptionResult);
} else {
logger.error("Subscription " + subName + " failed");
}
} }
createTangoAttributes(subscriptionResults); createTangoAttributes(subscriptionResults);
} }
...@@ -320,7 +324,7 @@ public class OpcUaSubscriber extends AOpcUaSubscriber { ...@@ -320,7 +324,7 @@ public class OpcUaSubscriber extends AOpcUaSubscriber {
if (connector.getState() != DeviceState.ON) { if (connector.getState() != DeviceState.ON) {
status = "Connector " + connectorDeviceName + " is not ON."; status = "Connector " + connectorDeviceName + " is not ON.";
} else if (connector.isConnected()) { } else if (connector.isConnected()) {
status = "Connected thru device "+ connectorDeviceName; status = "Connected via device " + connectorDeviceName;
} else { } else {
status = "Connector " + connectorDeviceName + " is not connected to an OPCUA server."; status = "Connector " + connectorDeviceName + " is not connected to an OPCUA server.";
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment