'Adding device to OPC-UA IoT Agent trough REST API call

I'm struggling trying to add a device via API call. If I start the docker container with the docker-compse.yml, I'm able to load a device to the local OPC-UA server, with the following REST API call.

curl http://localhost:4001/iot/devices -H "fiware-service: opcua_car" -H "fiware-servicepath: /demo" -H "Content-Type: application/json" -d @testCommands/add_device_NGSIv2.json

But, if I start the docker container with the docker-compse-external-server.yml, which instead of the iotagent4fiware/iotagent-opcua:latest uses the iotagent4fiware/iotagent-opcua:1.3.4, and I use the same API call, I get the following error:

{"name":"WRONG_SYNTAX","message":"Wrong syntax in request: Errors found validating request."}

From the Docker log:

"op":"IoTAgentNGSI.RestUtils","time":"2022-05-12T19:47:59.467Z","lvl":"DEBUG","msg":"Errors found validating request: {
    "valid":false,"errors": [
        {"attribute":"pattern","property":"devices.0.commands.1.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=Accelerate","message":"invalid input"},
        {"attribute":"pattern","property":"devices.0.commands.0.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=Stop","message":"invalid input"},
        {"attribute":"pattern","property":"devices.0.attributes.4.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=Oxigen","message":"invalid input"},
        {"attribute":"pattern","property":"devices.0.attributes.3.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=Temperature","message":"invalid input"},
        {"attribute":"pattern","property":"devices.0.attributes.2.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=EngineStopped","message":"invalid input"},
        {"attribute":"pattern","property":"devices.0.attributes.1.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=Acceleration","message":"invalid input"},
        {"attribute":"pattern","property":"devices.0.attributes.0.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=EngineBrake","message":"invalid input"},
        {"attribute":"pattern","property":"devices.0.lazy.0.object_id","expected":"^([^<>();'="]+)+$","actual":"ns=3;s=Speed","message":"invalid input"}
    ]
}

Then, If I run the Agent in Node.js, I get the same error:

{"name":"WRONG_SYNTAX","message":"Wrong syntax in request: Errors found validating request."}

If I try to use iotagent4fiware/iotagent-opcua:latest, which should be the same of running the cloned repository in Node.js, it seems to ignore the endpointUrl present in the configuration.properties file, and it try to connect always to opc.tcp://iotcarsrv:5001/UA/CarServer. Of course, connection fails...

I'm pretty confused from that behaviors, and I can't add anything to the IoTAgent.



Solution 1:[1]

Please try to use this curl to add a new device

curl --location --request POST 'http://localhost:4001/iot/devices' \
  --header 'fiware-service: opcua_car' \
  --header 'fiware-servicepath: /demo' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "devices": [
      {
        "device_id": "age03_Car",
        "entity_name": "age03_Car",
        "entity_type": "Device",
        "attributes": [
          {
            "object_id": "ns=3;s=EngineBrake",
            "name": "EngineBrake",
            "type": "Number"
          }, {
            "object_id": "ns=3;s=Acceleration",
            "name": "Acceleration",
            "type": "Number"
          }, {
            "object_id": "ns=3;s=EngineStopped",
            "name": "EngineStopped",
            "type": "Boolean"
          }, {
            "object_id": "ns=3;s=Temperature",
            "name": "Engine_Temperature",
            "type": "Number"
          }, {
            "object_id": "ns=3;s=Oxigen",
            "name": "Engine_Oxigen",
            "type": "Number"
          }, {
            "object_id": "ns=3;s=DataBlocksGlobal_3_dbRfidCntr_3_ID1_3_xBusy",
            "name": "DataBlocksGlobal_3_dbRfidCntr_3_ID1_3_xBusy",
            "type": "String"
          }, {
            "object_id": "ns=3;s=DataBlocksGlobal_3_dbRfidCntr_3_ID1_3_xBusyStatus",
            "name": "DataBlocksGlobal_3_dbRfidCntr_3_ID1_3_xBusyStatus",
            "type": "Boolean"
          }
        ],
        "lazy": [
          {
            "object_id": "ns=3;s=Speed",
            "name": "Speed",
            "type": "Number"
          }, {
            "object_id": "ns=3;s=GPSCoordinates",
            "name": "GPSCoordinates",
            "type": "Number"
          }
        ],
        "commands": [
          {
            "object_id": "ns=3;s=Stop",
            "name": "Stop",
            "type": "command"
          }, {
            "object_id": "ns=3;s=Accelerate",
            "name": "Accelerate",
            "type": "command"
          }, {
            "object_id": "ns=3;s=ActivateSensor",
            "name": "ActivateSensor",
            "type": "command"
          }, {
            "object_id": "ns=3;s=DeactivateSensor",
            "name": "DeactivateSensor",
            "type": "command"
          }, {
            "object_id": "ns=3;s=ToggleSensorActivation",
            "name": "ToggleSensorActivation",
            "type": "command"
          }, {
            "object_id": "ns=3;s=LaunchMissiles",
            "name": "LaunchMissiles",
            "type": "command"
          }
        ]
      }
    ]
  }

Solution 2:[2]

I found a way to make it work, looking at another issue on the repository. Using "*" instead of "=", and ":" instead of ";", I've overcome the syntax issue.

That syntax was present on the file testCommands\MultiDeviceTest\add_device_lazy_attrs.json but is not documented anyware.

Solution 3:[3]

AFAIK, Gson will ignore unknown fields automatically while deserialization. So, I assume that you have already created these 2 classes which look like:

public class MyClass {
    private Boolean myBool;

    // getter, setter and toString
}

public class MyResult {
    private Boolean firstProperty;
    private String thisIsAString;
    List<MyClass> myList;

    // getter, setter and toString
}

Then you can serialize your JSON string as follows:

String yourJsonStr = "" +
                "{\n" +
                "  \"firstProperty\": true,\n" +
                "  \"thisIsAString\": \"hi\",\n" +
                "  \"myList\": [\n" +
                "    {\"myBool\": true},\n" +
                "    {\"myBool\": false, \"otherfield\": true}\n" +
                "  ]\n" +
                "}";

Gson gson = new Gson();
MyResult myResult = gson.fromJson(yourJsonStr, MyResult.class);
System.out.println(myResult.toString());

Console output:

MyResult{firstProperty=true, thisIsAString='hi', myList=[MyClass{myBool=true}, MyClass{myBool=false}]}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tyler2P
Solution 2 drypatrick
Solution 3