OPC UA How to read a datatype from the server - opc

I can't seem to figure this one out:
Before writing to a tag I need to know what data type it is expecting(the value that mywrite function receives is always a string).
I realise you have to read the datatype from the server and here's my code to do so, but I'm at a loss as to how to use the information returned:
var nodesToRead = BuildReadValueIdCollection(node.DisplayName, Attributes.DataType);
DataValueCollection readResults;
DiagnosticInfoCollection diag;
_session.Read(
requestHeader: null,
maxAge: 0,
timestampsToReturn: TimestampsToReturn.Neither,
nodesToRead: nodesToRead,
results: out readResults,
diagnosticInfos: out diag);
var val = readResults[0];
What do I do with val to determine what the datatype is?
Do I use Val.Value or Val.WrappedValue or Val.WrappedValue.Value (whatever the difference is ?)
The tag I've been using to test has returned Val = "i=6".....
What is this referring to?
What datatype is "6" and
how do I convert val to something I can use.
Any help would be greatly appreciated.
Thanks

Reading from the DataType attribute returns a NodeID of the OPC UA type. It can be one of the "standard" types defined in the OPC UA spec, or something specific to the server. The standard types reside in namespace 0, which is your case (as there is no "ns=..." part in the displayed Node ID), and "i=6" stands for Int32.
There are many types with pre-defined Node IDs, and you need to consult the OPC UA specs, or the nodeset files that come with the stacks/SDKs (e.g. Opc.Ua.NodeSet.xml), to figure out what they mean.

The value is a NodeId referring to the data type node. You can compare the value to known NodeId values (DataTypeIds in .NET or something, not sure about this right away) or you will need to find the data type node from the address space.

In recent version, node-opcua client has been extended with a utility function ClientSession#getBuiltInDataType that does this for you.
var nodeId = coerceNodeId("ns=411;s=Scalar_Simulation_Int64");
session.getBuiltInDataType(nodeId,function(err,dataType){
if(!err){
console.log("Use data Type",dataType," to write into UAVariable", nodeId.toString();
}
});

We use this extension method to determine the C# type of nodes:
public static Type GetSystemType(this Session session, NodeId nodeId)
{
var currentValue = session.ReadValue(nodeId);
var builtInType = currentValue.WrappedValue.TypeInfo.BuiltInType;
var valueRank = currentValue.WrappedValue.TypeInfo.ValueRank;
return TypeInfo.GetSystemType(builtInType, valueRank);
}
It is somewhat a hack but it works well.

Related

Connect to a node with a String identifier

I'm trying to write a generic OPC-UA connector with Eclipse Milo.
Reading data from nodes already works fine when I'm using numeric nodeIDs, such as ns=0;i=2258. In milo I can simple construct the nodeID like this for example:
NodeId nodeIdentifier = new NodeId(Unsigned.ushort(nameSpaceID), uint(nodeID));
and it works fine.
But when I'm trying to connect to a note with a string identifier of a production node that only have a string identifier like shown in this image
the process fails with a StatusCode{name=Bad_NodeIdUnknown, value=0x80340000, quality=bad} exception.
I create the nodeIdentifier like this NodeId nodeIdentifier = NodeId.parse(nodeIDString);
and the parsed value looked like this:
ns=1;s=t|023_Messwert
First things first, you can’t just decide to use a string-based NodeId because you feel like it. If the server is exposing it as an integer-based NodeId then that’s what you have to use, as is the case with the CurrentTime Node being identified by ns=0;i=2258.
Parsing a string-based NodeId via NodeId.parse will work fine as long as it’s in the right format. What value are you trying to parse?

mirth connect Database Reader automatic column mapping

Please could somebody confirm the following..
I am using Mirth Connect 3.5.08232.
My Source Connector is a Database Reader.
Say, I am using a query that returns multiple rows, and return the result (via JavaScript), as documentation suggests, so that Mirth would treat each row as a separate message. I also use a couple of mappers as source transformers, and save the mapped fields in my channel map (which ends up to contain only those fields that I define in transformers)
In the destination, and specifically, in destination response transformer (or destination body, if it is a JavaScript writer), how do I access the source fields?
the only way I found by trial and error is
var rawMsg = connectorMessage.getRawData();
var xmlMsg = new XML(rawMsg);
logger.info(xmlMsg.some_field); // ignore the root element of rawMsg
Is this the right way to do this? I thought that maybe the fields that were nicely automatically detected would be put in some kind of a map, like sourceMap - but that doesn't seem to be the case, right?
Thank you
If you are using Mapper steps in your transformer to extract the data and put it into a variable map (like the channel map), then you can use any of the following methods to retrieve it from a subsequent JavaScript context (including a JavaScript Writer, and your response transformer):
var value = channelMap.get('key');
var value = $c('key');
var value = $('key');
Look at the Variable Maps section of the User Guide for more information.
So to recap, say you're selecting a column "mycolumn" with a Database Reader. The XML sent to the channel will be something like this:
<result>
<mycolumn>value</mycolumn>
</result>
Then you can choose to extract pieces of that message into specific variables for later use. The transformer allows you to easily drag-and-drop pieces of the sample inbound message.
Finally in your JavaScript Writer (or in any subsequent filter, transformer, or response transformer), just drag the value into the field you want:
And the corresponding JavaScript code will automatically be inserted:
One last note, if you are selecting a lot of variables and don't want to make Mapper steps for each one individually, you can use a JavaScript Step to iterate through the message and extract each column into a separate map variable:
for each (child in msg.children()) {
channelMap.put(child.localName(), child.toString());
}
Or, you can just reference the columns directly from within the JavaScript Writer:
var msg = new XML(connectorMessage.getEncodedData());
var column1 = msg.column1.toString();
var column2 = msg.column2.toString();
...

Orange3 : String Variable

I do not manage to create an Orange table with StringVariables.
The following code:
d = Orange.data.Domain([Orange.data.StringVariable("s")])
makes this error:
TypeError: variables must be primitive
It seems that StringVariable is for metadata only. So I'm worried about this because my data has a lot of strings that it would be crazy to put in a discrete structure (each string value is different).
Is there a solution for putting strings in a table ?
Thanks in advance for the answers,
Best,
mike
This question might be old but I found it via Google and wanted to provide a simple example of how to use meta "columns".
You need to specify the meta variables the same way you specify the "normal" variables just do it inside the metas parameter inside the Domain constructor.
from Orange.data import *
taskid = StringVariable(name="taskid")
logdata = StringVariable(name="logdata")
domain = Domain([] , metas=[taskid, logdata])
data = Table(domain, [
["uuid1","some more stuff"],
["uuid2","some more stuff"]
]);
out_data = data;

How to filter fields from the database in JSON response?

i am making a REST API in golang and i want to add support for filtering fields but i don't know the best way to implement that, lets say i have this structure representing an Album model
type Album struct {
ID uint64 `json:"id"`
User uint64 `json:"user"`
Name string `json:"name"`
CreatedDate time.Time `json:"createdDate"`
Privacy string `json:"privacy"`
Stars int `json:"stars"`
PicturesCount int `json:"picturesCount"`
}
and a function that returns an instance of an Album
func GetOne(id uint64, user uint64) (Album, error) {
var album Album
sql := `SELECT * FROM "album" WHERE "id" = $1 AND "user" = $2;`
err := models.DB.QueryRow(sql, id, user).Scan(
&album.ID,
&album.User,
&album.Name,
&album.CreatedDate,
&album.Privacy,
&album.Stars,
&album.PicturesCount,
)
return album, err
}
and the client was to issue a request like this
https://api.localhost.com/albums/1/?fields=id,name,privacy
obvious security issues aside, my first thought was to filter the fields in the database using something like this
func GetOne(id uint64, user uint64, fields string) {
var album Album
sql := fmt.Sprintf(`SELECT %s FROM "album" WHERE "id" = $1 AND "user" = $2;`, fields)
// i don't know what to do after this
}
and then i thought of adding omitempty tag to all the fields and setting the fields to their zero value before encoding it to JSON,
would this work?
which one is the better way?
is there a best way?
how would i go about implementing the first method?
Thank you.
For your first proposal (querying only the requested fields) there are two approaches (answering "would this work?" and "how would I go about implementing the first method?"):
Dynmaically reate a (possibly anonymous) struct and generate JSON from there using encoding/json.
Implement a wrapper that will translate the *database/sql.Rows you get back from the query into JSON.
For approach (1.), you will somehow need to create structs for any combination of attributes from your original struct. As reflect cannot create a new struct type at runtime, your only chance would be to generate them at compile time. The combinatorial explosion will bloat your binary, so do not do that.
Approach (2.) is to be handled with caution and can only be a last resort. Taking the list of requested fields and writing out JSON with the values you got from DB sounds straightforward and does not involve reflection. However your solution will be (very likely) much more unstable than encoding/json.
When reading your question I too thought about using the json:"omitempty" struct tag. And I think that it is the preferable solution. It does neither involve metaprogramming nor writing your own JSON encoder, which is a good thing. Just be aware of the implications in case some fields are missing (client side maybe has to account for that). You could query for all attributes always and override the unwanted ones using reflection.
In the end, all above solutions are suboptimal, and the best solution would be to not implement that feature at all. I hope you have a solid reason to make attributes variable, and I am happy to further clarify my answer based on your explaination. However, if one of the attributes of a resource is too large, it maybe should be a sub-resource.

Getting the column name (sspace) from an ospace property name

I can see from the following example how to get the table name of an OSpace type:
https://lowrymedia.com/2014/06/10/ef6-1-mapping-between-types-tables-including-derived-types/
But how do I go about getting the SSpace column name from an OSpace property name (i.e. CLR type property)?
By browsing the MetadataProperties from the corresponding CSpace property, I can see there is a "Configuration" entry containing the column name if changed using the Fluid API or ColumnAttribute, but the value of the entry is an internal class on EF's part. Is it at all possible?
I have browsed a few answers regarding this topic, but none of them take into account the Fluid API configuration.
P.S. the specific property I'm looking for is scalar, if that can simplify things...
Column Name
To get the column name, you have to first get the EdmProperty associated with that column in the “structural space” (SSpace). I provide code to do that below. Once you have the EdmProperty, the name of the column is simply EdmProperty.Name:
string GetColumnName(DbContext context, PropertyInfo property) {
return GetStructuralSpaceEdmProperty(context, property).Name;
}
Structural Space Property
This is based on an article. That article gives you enough information to map all the way to the structural EntityType. I added a bit at the end to do the actual property mapping to get the EdmProperty representing the column. As the article states, these APIs require ≥EntityFramework-6.1.
EdmProperty GetStructuralSpaceEdmProperty(DbContext context, PropertyInfo property) {
IObjectContextAdapter adapter = context;
var metadata = adapter.ObjectContext.MetadataWorkspace;
// First, you map the Object Space to the Conceptual Space.
var objectItemCollection = (ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace);
var objectEntityType = metadata.GetItems<EntityType>(DataSpace.OSpace)
.Single(oet => objectItemCollection.GetClrType(oet) == property.DeclaringType);
// Note: we are assuming that CSpace and OSpace name their properties the
// same instead of trying to use EF’s own OSSpace mappings here.
var conceptualEntityType = metadata.GetItems<EntityType>(DataSpace.CSpace)
.Single(cet => objectEntityType.Name == cet.Name);
var conceptualEdmProperty = conceptualEntityType.Properties
.Single(ep => ep.Name == property.Name);
// Then you map the conceptual space onto the structural space.
var entitySet = metadata.GetItems<EntityContainer>(DataSpace.CSpace)
.Single().EntitySets
.Single(es => es.ElementType.Name == conceptualEntityType.Name);
var entityMapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
.Single().EntitySetMappings
.Single(esm => esm.EntitySet == entitySet);
// The entity may be split to different tables or fragments.
var fragments = entityMapping.EntityTypeMappings
.SelectMany(etm => etm.Fragments);
var propertyMappings = fragments.SelectMany(f => f.PropertyMappings);
// Normal properties will be “ScalarPropertyMapping”.
// Depending on what information you are seeking or your
// model, you may be interested in other PropertyMapping.
var structuralSpaceProperty = propertyMappings
.OfType<ScalarPropertyMapping>()
.Single(pm => pm.Property == conceptualEdmProperty).Column;
return structuralSpaceProperty;
}
Note that once you have EdmProperty in structural space, there are a bunch of other useful properties you can read from it. For example, for SQL Server, EdmProperty.IsUnicode will be true for NVARCHAR/NCHAR and false for VARCHAR/CHAR types whereas this property is not set to a useful value in the conceptual space.
Random Information
Spaces in EF
Alex D. James’s blog post “Tip 10 — How to understand Entity Framework jargon” explains some of the terms of the API which do not make sense on their own. DataSpace.OSpace stands for “Object Space”, meaning the .net POD classes. DataSpace.SSpace stands for “Structural Space”, probably named after “structured” in the term “SQL” and thus meaning it most directly describes the backend database. DataSpace.CSpace stands for “Conceptual Space” which seems intended to be a neutral space which both the “Object Space” and “Structural Space” can map into. DataSpace.OCSpace stands for the mapping from the object space onto the conceptual space. We bypass this mapping because we assume that property names in the object space are the same as in our .net types. DataSpace.CSSpace stands for the mapping of conceptual space onto structural space. We use this mapping because the model may be configured to use a different column name via the fluent API or ColumnAttribute.
API Confusion
The metadata API of EF seems to assume that the consumer of the API has an understanding of the internals of EF to an extent. It is not made in a very type safe way which helps consumers. For example, the fact that we had to use Enumerable.OfType<TResult> to get to ScalarPropertyMapping means that one has to know to expect the collection to have ScalarPropertyMapping instances in it. Likewise, the MetadataWorkspace.GetItems<T>() method requires us to know that the sorts of items one would find in the metadata include EntityType. Thus, a deep understanding of the internals of EF or complete examples are necessary to write code that consumes the mapping portion of these APIs.