eclipse-basyx / basyx-databridge

Eclipse Public License 2.0
11 stars 18 forks source link

Error transfering string values from OPC UA server to AAS #223

Closed aaronzi closed 2 weeks ago

aaronzi commented 1 year ago

After 2-3 successful requests of a string property, the Databridge throws an error for the corresponding route:

2023-05-20 12:02:27 [Camel (camel-1) thread #1 - timer://foo] INFO route1 - Source : route1
2023-05-20 12:02:27 [Camel (camel-1) thread #1 - timer://foo] ERROR org.apache.camel.processor.errorhandler.DefaultErrorHandler - Failed delivery for (MessageId: 6CB21D9ED1C9C73-0000000000000000 on ExchangeId: 6CB21D9ED1C9C73-0000000000000000). Exhausted after delivery attempt: 1 caught: java.lang.NullPointerException
2023-05-20 12:02:27 
2023-05-20 12:02:27 Message History (source location and message history is disabled)
2023-05-20 12:02:27 ---------------------------------------------------------------------------------------------------------------------------------------
2023-05-20 12:02:27 Source                                   ID                             Processor                                          Elapsed (ms)
2023-05-20 12:02:27                                          route1/route1                  from[timer://foo?delay=0&fixedRate=true&period=100      8104676
2023-05-20 12:02:27     ...
2023-05-20 12:02:27                                          route1/to2                     jsonata:file:/tmp/dataBridge/jsonataExtractValue.j            0
2023-05-20 12:02:27 
2023-05-20 12:02:27 Stacktrace
2023-05-20 12:02:27 ---------------------------------------------------------------------------------------------------------------------------------------
2023-05-20 12:02:27 java.lang.NullPointerException
2023-05-20 12:02:27     at org.apache.camel.component.jsonata.JsonataEndpoint.onExchange(JsonataEndpoint.java:120)
2023-05-20 12:02:27     at org.apache.camel.support.ProcessorEndpoint$1.process(ProcessorEndpoint.java:61)
2023-05-20 12:02:27     at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66)
2023-05-20 12:02:27     at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)
2023-05-20 12:02:27     at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477)
2023-05-20 12:02:27     at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:181)
2023-05-20 12:02:27     at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59)
2023-05-20 12:02:27     at org.apache.camel.processor.Pipeline.process(Pipeline.java:165)
2023-05-20 12:02:27     at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:392)
2023-05-20 12:02:27     at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210)
2023-05-20 12:02:27     at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)
2023-05-20 12:02:27     at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
2023-05-20 12:02:27     at java.base/java.util.TimerThread.run(Timer.java:506)
2023-05-20 12:02:27 [Camel (camel-1) thread #1 - timer://foo] WARN org.apache.camel.component.timer.TimerConsumer - Error processing exchange. Exchange[6CB21D9ED1C9C73-0000000000000000]. Caused by: [java.lang.NullPointerException - null]
2023-05-20 12:02:27 java.lang.NullPointerException
2023-05-20 12:02:27     at org.apache.camel.component.jsonata.JsonataEndpoint.onExchange(JsonataEndpoint.java:120)
2023-05-20 12:02:27     at org.apache.camel.support.ProcessorEndpoint$1.process(ProcessorEndpoint.java:61)
2023-05-20 12:02:27     at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66)
2023-05-20 12:02:27     at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)
2023-05-20 12:02:27     at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477)
2023-05-20 12:02:27     at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:181)
2023-05-20 12:02:27     at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59)
2023-05-20 12:02:27     at org.apache.camel.processor.Pipeline.process(Pipeline.java:165)
2023-05-20 12:02:27     at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:392)
2023-05-20 12:02:27     at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:210)
2023-05-20 12:02:27     at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)
2023-05-20 12:02:27     at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
2023-05-20 12:02:27     at java.base/java.util.TimerThread.run(Timer.java:506)

The jsonataExtractValue transformer throws a NullpointerException because the requested resource body is null. The reason for that is unclear. UAExpert can read the string value as expected.

This is what the first working request looks like in the log for the exact same route:

2023-05-20 12:02:13 [main] INFO org.eclipse.digitaltwin.basyx.components.databridge.core.component.DataBridgeComponent - Updater started
2023-05-20 12:02:14 [Camel (camel-1) thread #1 - timer://foo] INFO org.apache.camel.component.milo.client.internal.SubscriptionManager - Starting connect
2023-05-20 12:02:14 [Camel (camel-1) thread #1 - timer://foo] INFO org.eclipse.milo.opcua.sdk.client.OpcUaClient - Java version: 11.0.16
2023-05-20 12:02:14 [Camel (camel-1) thread #1 - timer://foo] INFO org.eclipse.milo.opcua.sdk.client.OpcUaClient - Eclipse Milo OPC UA Stack version: 0.6.8
2023-05-20 12:02:14 [Camel (camel-1) thread #1 - timer://foo] INFO org.eclipse.milo.opcua.sdk.client.OpcUaClient - Eclipse Milo OPC UA Client SDK version: 0.6.8
2023-05-20 12:02:14 [milo-nonce-util-secure-random] INFO org.eclipse.milo.opcua.stack.core.util.NonceUtil - SecureRandom seeded in 0ms.
2023-05-20 12:02:15 [Camel (camel-1) thread #1 - timer://foo] INFO route1 - Source : route1
2023-05-20 12:02:15 [Camel (camel-1) thread #1 - timer://foo] INFO route1 - Exchange[ExchangePattern: InOnly, BodyType: String, Body: "Universal Robots"]
2023-05-20 12:02:16 [Camel (camel-1) thread #1 - timer://foo] INFO org.eclipse.digitaltwin.basyx.components.databridge.aas.AASProducer - Transferred message="Universal Robots" with valueType=string
2023-05-20 12:02:16 [Camel (camel-1) thread #1 - timer://foo] INFO route1 - Exchange[ExchangePattern: InOnly, BodyType: String, Body: "Universal Robots"]

An example to reproduce the issue can be found in the repository BaSyx Applications (https://github.com/eclipse-basyx/basyx-applications). There is a folder called opc2aas. In there is a DatabridgeDemo where this issue occurs.

sureshmoon commented 1 year ago

Hi, I got the similar error and solved by change the 'DatabridgeConfig/routes.json -> trigger: from "timer" to "event". But I don't know how to solve if someone still wants to use "timer" trigger option.

aaronzi commented 1 year ago

Thank you very much @sureshmoon, that indeed helped with the problem :)

FrankSchnicke commented 1 year ago

Thank you very much for pointing this out. We looked at the internals of how OPC UA is handled by Apache Camel and came to the realization that for OPC UA, a timer-driven approach does not provide any benefits in contrast to an event-driven approach while at the same time, using events solves the stated issue.

In consequence, we updated the wiki and examples to utilize only "event" as "trigger".

as17050 commented 1 month ago

Hi @aaronzi i also have this Databridge error that you mentioned above and i changed the in the trigger in routes.jsons to event also but somehow it doesn't seem working. I can see the value=20 in log which i have manually written from the OPC-UA server but i cant see it in the AAS UI viewer. I have raspberry pi where the OPC-UA server is running. Do you still have this issue?

databridge    | [milo-shared-thread-pool-1] INFO route1 - Exchange[ExchangePattern: InOnly, BodyType: org.eclipse.milo.opcua.stack.core.types.builtin.DataValue, Body: DataValue{value=Variant{value=20}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=133739098706750000, javaDate=Sun Oct 20 14:57:50 UTC 2024}, serverTime=DateTime{utcTime=133739098706750000, javaDate=Sun Oct 20 14:57:50 UTC 2024}}]
databridge    | [milo-shared-thread-pool-1] ERROR org.apache.camel.processor.errorhandler.DefaultErrorHandler - Failed delivery for (MessageId: 66DF41632114304-0000000000000001 on ExchangeId: 66DF41632114304-0000000000000001). Exhausted after delivery attempt: 1 caught: java.lang.NullPointerException
databridge    |
databridge    | Message History (source location and message history is disabled)
databridge    | ---------------------------------------------------------------------------------------------------------------------------------------
databridge    | Source                                   ID                             Processor                                          Elapsed (ms)
databridge    |                                          route1/route1                  from[milo-client://opc.tcp://192.168.0.156:4840/mi     21002833
databridge    |         ...
databridge    |                                          route1/to3                     jsonata:file:/tmp/dataBridge/jsonataExtractValue.j            0
databridge    |
databridge    | Stacktrace
databridge    | ---------------------------------------------------------------------------------------------------------------------------------------
databridge    | java.lang.NullPointerException
databridge    |         at org.apache.camel.component.jsonata.JsonataEndpoint.onExchange(JsonataEndpoint.java:120)
databridge    |         at org.apache.camel.support.ProcessorEndpoint$1.process(ProcessorEndpoint.java:61)
databridge    |         at org.apache.camel.support.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:66)
databridge    |         at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)
databridge    |         at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477)
databridge    |         at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:181)
databridge    |         at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59)
databridge    |         at org.apache.camel.processor.Pipeline.process(Pipeline.java:165)
databridge    |         at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:392)
databridge    |         at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
databridge    |         at org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41)
databridge    |         at org.apache.camel.component.milo.client.MiloClientConsumer.handleValueUpdate(MiloClientConsumer.java:82)
databridge    |         at org.eclipse.milo.opcua.sdk.client.subscriptions.OpcUaMonitoredItem.lambda$setValueConsumer$0(OpcUaMonitoredItem.java:152)
databridge    |         at org.eclipse.milo.opcua.sdk.client.subscriptions.OpcUaMonitoredItem.onValueArrived(OpcUaMonitoredItem.java:212)
databridge    |         at org.eclipse.milo.opcua.sdk.client.subscriptions.OpcUaSubscriptionManager.lambda$null$44(OpcUaSubscriptionManager.java:733)
databridge    |         at org.eclipse.milo.opcua.stack.core.util.ExecutionQueue$Task.run(ExecutionQueue.java:119)
databridge    |         at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
databridge    |         at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
databridge    |         at java.base/java.lang.Thread.run(Thread.java:829)
aaronzi commented 1 month ago

Hi, I don't have this issue anymore. Can you share your databridge config files so that we are able to reproduce the problem.

as17050 commented 1 month ago

Hi @aaronzi thanks for you reply here are the config files that i used. I dont use the string values likewise in this post from you but its not working for any datatype. In the example i am just using a single sensorvalue.

databridge_conf.zip Basyx_setup.zip

aaronzi commented 1 month ago

Ok, now I see the problem. You are missing a jsonJackson transformer to convert the data coming from the OPC UA server to json so that the jsonata transformer can work with it.

Please have a look at this example: https://github.com/eclipse-basyx/basyx-databridge/tree/main/databridge.examples/databridge.examples.opcua-jackson-jsonata-aas/src/main/resources

You need this transformer which has to be executed before the jsonata transformer:

[
    {
        "uniqueId": "dataValueToJson",
        "operation": "marshal",
        "jacksonModules": "com.fasterxml.jackson.datatype.jsr310.JavaTimeModule"
    }
]

Here is what the route will look like:


[
    {
        "datasource": "EF_i_iSensorValue",
        "transformers": ["dataValueToJson", "jsonataA"],
        "datasinks":["Energy_data_iSensorValue"],
        "trigger": "event"
    }
]
as17050 commented 1 month ago

I tried that example also but its throwing the Null exception. In the beginning i tried with that example itself but in both cases i am having an error image here is the new config file databridge_conf.zip

aaronzi commented 1 month ago

There is also a mistake in the aasserver.json. The submodelEndpoint should only include the URL of the submodel without the idShortPath. The correct config would look like this:

[
    {
        "uniqueId": "Energy_data_iSensorValue",
    "submodelEndpoint": "http://192.168.0.156:8081/submodels/c21hcnQuZmVzdG8uY29tL2lkcy9zbS84NDEyXzcwMTJfMDEwMl82OTM0",
    "idShortPath": "EF_i_iSensorValue"
    }
]
as17050 commented 1 month ago

I did that too but doesn't work. It's throwing the null exception.

as17050 commented 2 weeks ago

HI @aaronzi i thing this might be the problem. If you see the submodel endpoint url highlighted as red in the photo attached below the url is http://192.168.0.160:8081/submodels/c21hcnQuZmVzdG8uY29tL2lkcy9zbS84NDEyXzcwMTJfMDEwMl82OTM0/submodelElements/EF_i_iSensorValue

but the actual url in the UI of my aas viewer is different. In stead of "submodelElements" its "submodel-endpoints". If i use the http request on this url which has "submodel-endpoints" and get the value with a python script then i get the acrual value, Currently i am using the python opc-ua client and transfer that value on the opc-ua node and vice-a-versa. here is the actual url in my aas-viewer

http://192.168.0.160:8081/submodels/c21hcnQuZmVzdG8uY29tL2lkcy9zbS84NDEyXzcwMTJfMDEwMl82OTM0/submodel-elements/EF_i_iSensorValue

is there any way to change this in the configuration so that the databridge gets the same submodel endpoint url as above.

databridge_log

aaronzi commented 2 weeks ago

You are using BaSyx Java V2 (AAS V3) right? If yes, you should set the "api": "DotAAS-V3" like this for every entry in the aasserver.json. An entry could look like this:

[
  {
    "uniqueId": "ConnectedTestSubmodel/DotAASV3ConformantApiSMC/DotAASV3ConformantApiProperty",
    "submodelEndpoint": "http://localhost:4001/submodels/c3VibW9kZWxJZA==",
    "idShortPath": "DotAASV3ConformantApiSMC.DotAASV3ConformantApiProperty",
    "api": "DotAAS-V3"
  }
]

If you don't do this, the Databridge will use the old URL Pattern of BaSyx V1.

as17050 commented 2 weeks ago

now it works. Thanks for the inputs and your help!!

as17050 commented 2 weeks ago

@aaronzi my databrige is working now with the opc-ua communication but it works only if i read the data from opc-ua nodes but if i want write something from aas to opc-ua it doesn't work. I have seen one issue where the two-way communication is not supported at the moment but seems like its an old post. Is there anything i am missing again in the configuration where i need to change? Currently i am running the python scripts to do that but i would also like to try it with the databridge.

aaronzi commented 2 weeks ago

This is a type mapping issue. As mentioned here, only OPC UA nodes of type variant (strings) are supported. Hopefully we will find a solution for this after upgrading to the latest version of Apache Kafka. For now, we have to live with the limitations.