AssetConnection
The AssetConnection interface is responsible for synchronizing values of the model with assets. Although asset synchronization is not part of the AAS specification, we believe this functionality is essential for digital twins, at least when located on edge-level, i.e., close to an actual machine/asset.
The following figure depicts how asset synchronization works in more detail.
The top half shows a examplenary AAS model that we want to synchronize with the underlying asset. In the center we have the AssetConnection interface which holds multiple of so-called Providers. There are three types of providers:
ValueProvider: for reading data from and writing data to to asset whenever the value of the corresponding AAS element is read/written
OperationProvider: for forwarding operation invocation requests to the asset and translating the response back to be AAS-compliant
SubscriptionProvider: for subscribing to changes on the asset and therefore continuously updating the value of the corresponding AAS element
The mapping between AAS elements and providers is defined in the configuration of the AssetConnection. Therefore, the configuration section for all implementations of the AssetConnection interface share the following common structure.
1{
2 "assetConnections": [ {
3 "@class": "...",
4 // connection-level configuration
5 "valueProviders":
6 {
7 "{serialized Reference of AAS element}":
8 {
9 // value provider configuration
10 }
11 },
12 "operationProviders":
13 {
14 "{serialized Reference of AAS element}":
15 {
16 // operation provider configuration
17 }
18 },
19 "subscriptionProviders":
20 {
21 "{serialized Reference of AAS element}":
22 {
23 // subscription provider configuration
24 }
25 }
26 }],
27 //...
28}
The value of {serialized Reference of AAS element}
is the Reference to the AAS element serialized using the rules described in Section 7.2.3 of AAS Specification - Part 1.
An example value could look like this [ModelRef](Submodel)urn:aas:id:example:submodel:1, (Property)Property1
.
Important
The format for serializing references has changed with AAS v3.0 resp. FA³ST Service v1.0. For example, the id type is now no longer part of the serialization and path elements are now separated by ,
(comma followed by space) instead of ,
(comma).
The available configuration properties for connection-level and the providers are implementation-specific. This is necessary because different protocols require different types of information, e.g. for OPC UA an AAS element could be mapped to an OPC UA node which means the configuration must contain the node ID, while for MQTT we need a topic on which to listen and maybe even information about the payload format.
Note
An implementation does not have to implement all three provider types. In fact, it is often not possible to implement all of them for a given network protocol as most protocols do not support pull-based and pub/sub mechanisms at the same time (e.g. HTTP, MQTT).
Tip
You can define both a ValueProvider and a SubscriptionProvider for the same element. This allows you to reflect in the asset changes in near real-time in your AAS and at the same time to update the value on the asset via the AAS API. This is especially useful when starting FA³ST with an OPC UA endpoint as it allows users to subscribe to changes or AAS properties via OPC UA.
OperationProvider Configuration
All OperationProvider share the following common set of configuration properties.
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
inputValidationMode |
NONE |
Validation mode for input arguments |
REQUIRE_PRESENT_OR_DEFAULT |
inoutputValidationMode |
NONE |
Validation mode for inoutput arguments |
REQUIRE_PRESENT_OR_DEFAULT |
outputValidationMode |
NONE |
Validation mode for ouput arguments |
REQUIRE_PRESENT_OR_DEFAULT |
Validation of operation arguments
Validation of operation argument can be configured independently for in-, out-, and inoutput arguments to be one of the following values
NONE: no validation at all is performed
REQUIRE_PRESENT: requires all arguments defined for the operation to be provided in the call and all arguments provided to be defined for the operation. This check works only on argument name (idShort) and not argument datatype.
REQUIRE_PRESENT_OR_DEFAULT: sets all arguments defined for the operation but not provided in the call to the default value, i.e. the value given in the definition of the argument. Similar to REQUIRE_PRESENT, this requires the call to only contain arguments that are defined for the operation and works only on argument name ignoring the argument datatype.
HTTP
Supported Providers
ValueProvider
read ✔️
write ✔️
OperationProvider ✔️
SubscriptionProvider ✔️ (via polling)
Configuration
Connection-Level
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
baseUrl |
String |
Base URL of the HTTP server, e.g. http://example.com. |
|
headers |
Map<String,String> |
Headers to send with each request. |
empty list |
password |
String |
Password for connecting to the HTTP server. |
|
trustedCertificates |
Trusted certificates, i.e. when connecting to a server that is using self-signed certificates. |
||
username |
String |
Username for connecting to the HTTP server. |
Value Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
format |
JSON |
Content format of the payload. |
|
headers |
Map<String,String> |
Headers to send with each request. |
empty list |
path |
String |
Path for the HTTP request, relative to the |
|
query |
String |
Additional information how to extract actual value from received messages. |
|
template |
String |
Template used to format payload when sending via HTTP. |
|
writeMethod |
GET |
HTTP method to use when writing a value to HTTP. |
PUT |
1{
2 "format": "JSON",
3 "path": "/foo",
4 "headers": {
5 "foo": "bar"
6 },
7 "query": "$.foo",
8 "template": "{\"foo\" : \"${value}\"}",
9 "writeMethod": "POST"
10}
Operation Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
format |
JSON |
Content format of the payload. |
|
headers |
Map<String,String> |
Headers to send with each request. |
empty list |
inputValidationMode |
NONE |
Validation mode for input arguments |
REQUIRE_PRESENT_OR_DEFAULT |
inoutputValidationMode |
NONE |
Validation mode for inoutput arguments |
REQUIRE_PRESENT_OR_DEFAULT |
method |
PUT |
HTTP method to use. |
POST |
outputValidationMode |
NONE |
Validation mode for ouput arguments |
REQUIRE_PRESENT_OR_DEFAULT |
path |
String |
Path for the HTTP request, relative to the |
|
queries |
Map<String,String> |
Map of result variable idShorts and corresponding query expressions to fetch them from returned value |
|
template |
String |
Template used to format payload when sending via HTTP. |
1{
2 "format": "JSON",
3 "path": "/foo/execute",
4 "headers": {
5 "foo": "bar"
6 },
7 "method": "POST",
8 "template": "{\"input1\" : \"${in1}\", \"input2\" : \"${in2}\"}",
9 "queries": {
10 "out1": "$.output1",
11 "out2": "$.output2"
12 }
13}
Subscription Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
format |
JSON |
Content format of the payload. |
|
headers |
Map<String,String> |
Headers to send with each request. |
empty list |
interval |
long |
Interval to poll the server for changes (in ms). |
100 |
method |
GET |
HTTP method to use when writing a value to HTTP. |
GET |
path |
String |
Path for the HTTP request, relative to the |
|
payload |
String |
Static content to send with each request. |
|
query |
String |
Additional information how to extract actual value from received messages. |
1{
2 "path": "/foo",
3 "headers": {
4 "foo": "bar"
5 },
6 "interval": "500",
7 "method": "GET",
8 "template": "{\"foo\" : \"bar\"}"
9}
MQTT
Supported Providers
ValueProvider
read ❌
write ✔️
OperationProvider ❌
SubscriptionProvider ✔️
Configuration
Connection-Level
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
clientId |
String |
Id of the MQTT client used to connect to the server |
randomly generated |
password |
String |
Password for connecting to the MQTT server |
|
serverUri |
String |
URL of the MQTT server, e.g. tcp://localhost:1883 |
|
username |
String |
Username for connecting to the MQTT server |
Value Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
format |
JSON |
Content format of the payload. |
|
topic |
String |
MQTT topic to use. |
|
template |
String |
Template used to format payload. |
1{
2 "format": "JSON",
3 "topic": "example/myTopic",
4 "template": "{\"foo\" : \"${value}\"}"
5}
Subscription Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
format |
JSON |
Content format of the payload. |
|
topic |
String |
MQTT topic to use. |
|
query |
String |
Additional information how to extract actual value from received messages. |
1{
2 "format": "JSON",
3 "topic": "example/myTopic",
4 "query": "$.foo"
5}
OPC UA
Supported Providers
ValueProvider
read ✔️
write ✔️
OperationProvider ✔️
SubscriptionProvider ✔️
Configuration
Connection-Level
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
acknowledgeTimeout |
Integer |
Timeout for acknowledgement (in ms). |
10000 |
applicationCertificate |
The application certificate. |
||
authenticationCertificate |
The authentication/user certificate. |
||
host |
String |
URL of the OPC UA server, e.g. opc.tcp://localhost:4840 |
|
password |
String |
Password for connecting to the OPC UA server. |
|
requestTimeout |
int |
Timeout for requests (in ms) |
3000 |
securityBaseDir |
String |
Base directory for the certificate handling. |
. |
securityMode |
None |
Security Mode for the connection to the OPC UA server. |
None |
securityPolicy |
None |
Desired Security Policy for the connection to the OPC UA server. |
None |
transportProfile |
TCP_UASC_UABINARY |
Transport Profile for the connection to the OPC UA server. |
TCP_UASC_UABINARY |
username |
String |
Username for connecting to the OPC UA server. |
|
userTokenType |
Anonymous |
User Token Type for connecting to the OPC UA server. |
Anonymous |
Remarks on certificate management
In OPC UA , certificates can be used for two purposes:
encryption & signing of messages, and
authentication of a client.
We call the certificate used for encryption application certificate and the one used for authenticating a client authentication certificate. You can choose to use only one of these options or both. If using both, you can use different or the same certificates.
Application Certificate
An application certificate is required if the property securityMode
is set to Sign
or SignAndEncrypt
.
Which application certificate to use is determined by the following steps:
applicationCertificate.keyStorePath
if it is an absolute file path and the file exists (default: application.p12){securityBaseDir}/{applicationCertificate.keyStorePath}
if the file exists (default:./{applicationCertificate.keyStorePath}
)otherwise generate self-signed certificate and store it at
applicationCertificate.keyStorePath
(ifapplicationCertificate.keyStorePath
is an absolute file path) or else{securityBaseDir}/{applicationCertificate.keyStorePath}
. The generated keystore will not be password protected.
You also need to make sure that the OPC UA client (which in this case is the FA³ST Service OPC UA asset connection) knows and trusts the server certificate and vice versa.
For the client to trust the server you need to do one of these steps depending on the certificate of the server:
Self-signed-certificate: Put server certificate in {securityBaseDir}/pki/trusted/certs
CA Certificate: put the CA root certificate in {securityBaseDir}/pki/issuers/certs and the corresponding certificate revocation list (CRL) in {securityBaseDir}/pki/issuers/crl.
If you don’t have the server certificate at hand you can start FA³ST Service without providing/trusting the server certificate.
On start-up FA³ST Service will try to connect to the server which will fail because the server certificate is not trusted yet.
After that you will find the relevant files at {securityBaseDir}/pki/rejected
.
Copy them to the respective directories as described above.
Once FA³ST Service tries to reconnect the connection should be established successfully.
For the server to trust your client application certificate please refer to the documentation of your OPC UA server.
Authentication Certificate
Which authentication certificate is used is determined by a similar logic as for the application certificate besides that this certificate is not auto-generated if not present:
authenticationCertificate.keyStorePath
if it is an absolute file path and the file exists (default: application.p12){securityBaseDir}/{authenticationCertificate.keyStorePath}
if the file exists (default:./{authenticationCertificate.keyStorePath}
)
Value Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
arrayIndex |
String |
Index of the desired array element if the node is an array. |
|
nodeId |
String |
NodeId of the the OPC UA node to read/write in ExpandedNodeId format |
1{
2 "nodeId": "nsu=com:example;s=foo",
3 "arrayIndex" : "[2]"
4}
Operation Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
inputArgumentMapping |
List |
List of mappings for input arguments between the idShort of a SubmodelElement and an argument name |
empty list |
inputValidationMode |
NONE |
Validation mode for input arguments |
REQUIRE_PRESENT_OR_DEFAULT |
inoutputValidationMode |
NONE |
Validation mode for inoutput arguments |
REQUIRE_PRESENT_OR_DEFAULT |
nodeId |
String |
NodeId of the the OPC UA node to read/write in ExpandedNodeId format |
|
outputArgumentMapping |
List |
List of mappings for output arguments between the idShort of a SubmodelElement and an argument name |
empty list |
outputValidationMode |
NONE |
Validation mode for ouput arguments |
REQUIRE_PRESENT_OR_DEFAULT |
parentNodeId |
String |
NodeId of the OPC UA object in ExpandedNodeId format, in which the method is contained. |
1{
2 "nodeId": "nsu=com:example;s=foo",
3 "parentNodeId": "nsu=com:example;s=fooObject",
4 "inputArgumentMapping": [ {
5 "idShort": "ExampleInputId",
6 "argumentName": "ExampleInput"
7 } ],
8 "outputArgumentMapping": [ {
9 "idShort": "ExampleOutputId",
10 "argumentName": "ExampleOutput"
11 } ]
12}
Subscription Provider
Name |
Allowed Value |
Description |
Default Value |
---|---|---|---|
arrayIndex |
String |
Index of the desired array element if the node is an array. |
|
interval |
long |
Interval to poll the server for changes (in ms) |
1000 |
nodeId |
String |
NodeId of the the OPC UA node to read/write in ExpandedNodeId format |
1{
2 "nodeId": "nsu=com:example;s=foo",
3 "interval": 1000,
4 "arrayIndex" : "[2]"
5}
Complete Example
1{
2 "@class": "de.fraunhofer.iosb.ilt.faaast.service.assetconnection.opcua.OpcUaAssetConnection",
3 "host": "opc.tcp://localhost:4840",
4 "securityPolicy": "None",
5 "securityMode" : "None",
6 "applicationCertificate": {
7 "keyStoreType": "PKCS12",
8 "keyStorePath": "C:\faaast\MyKeyStore.p12",
9 "keyStorePassword": "changeit",
10 "keyAlias": "app-cert",
11 "keyPassword": "changeit"
12 },
13 "authenticationCertificate": {
14 "keyStoreType": "PKCS12",
15 "keyStorePath": "C:\faaast\MyKeyStore.p12",
16 "keyStorePassword": "changeit",
17 "keyAlias": "auth-cert",
18 "keyPassword": "changeit"
19 },
20 "valueProviders": {
21 "[ModelRef](Submodel)urn:aas:id:example:submodel:1, (Property)Property1": {
22 "nodeId": "some.node.id.property.1"
23 },
24 "[ModelRef](Submodel)urn:aas:id:example:submodel:1, (Property)Property2": {
25 "nodeId": "some.node.id.property.2"
26 }
27 },
28 "operationProviders": {
29 "[ModelRef](Submodel)urn:aas:id:example:submodel:1, (Operation)Operation1": {
30 "nodeId": "some.node.id.operation.1"
31 }
32 },
33 "subscriptionProviders": {
34 "[ModelRef](Submodel)urn:aas:id:example:submodel:1, (Property)Property3": {
35 "nodeId": "some.node.id.property.3",
36 "interval": 1000
37 }
38 }
39}