Skip to main content

Sending Commands to Machines

Introduction

Commanding is about sending synchronous specific commands from an application to a tapio connected machine.

One example use case for commanding would be an operator, who starts the glue heating of a machine from home, in order to start working without any delay.

Sending specific commands in an synchronous manner, allows to execute a command on one or even multiple machines. For more information about executing commands see Execute a new command.

The commanding feature is only available from the version '6.0.19015.58385' or higher.

Configuration

A tapio connected machine can only accept commands if the configuration of the CloudConnector allows it. The following excerpt shows how the CloudConnector should be configured to enable the commanding feature:

<Module xsi:type="DataModuleConfig">
<Id>DataModule</Id>
<Source>
<Servers>
<SourceBase xsi:type="SourceOpcUa">
<Id>UniqueId01</Id>
<ApplicationUri>urn:VenjakobOpcUaServer</ApplicationUri>
<RemoteLds />

If required fields are not set, no error occurs at CloudConnector startup. Instead, when you invoke this command, you receive an "Unsupported" response Predefined command misconfigured

Insert the Commanding section as shown in the following example:

            <Commanding>
<Commands>
<Command xsi:type="CommandMethodCall">
<Id>Command-Id-01</Id> <!-- required -->
<TapioMachineId>vjkz1807001001</TapioMachineId> <!-- required -->
<ObjectNodeId>Optional node id</ObjectNodeId> <!-- required -->
<MethodNodeId>MethodName01-NodeId</MethodNodeId> <!-- required -->
<Arguments>
<Argument>
<Name>Argument01</Name>
<Value type="string">NewSawFileAvailable</Value>
</Argument>
</Arguments>
</Command>
<!-- Method without value for the argument -->
<Command xsi:type="CommandMethodCall">
<Id>Command-Id-01</Id> <!-- required -->
<TapioMachineId>vjkz1807001001</TapioMachineId> <!-- required -->
<ObjectNodeId>Optional node id</ObjectNodeId> <!-- required -->
<MethodNodeId>MethodName01-NodeId</MethodNodeId> <!-- required -->
<Arguments>
<!-- No argument has set a value - so you have to send the value in your command -->
</Arguments>
</Command>
<Command xsi:type="CommandItemWrite">
<Id>MainHeating-On</Id> <!-- required -->
<TapioMachineId>vjkz1807001001</TapioMachineId> <!-- required -->
<NodeId>ns=2;s=Framework.SoftKeys.003.Value</NodeId> <!-- required -->
<Value type="UInt32">2</Value> <!-- default type is string -->
</Command>
<!-- Write command without predefined value -->
<Command xsi:type="CommandItemWrite">
<Id>MainHeating-On</Id> <!-- required -->
<TapioMachineId>vjkz1807001001</TapioMachineId> <!-- required -->
<NodeId>ns=2;s=Framework.SoftKeys.003.Value</NodeId> <!-- required -->
</Command>
<Command xsi:type="CommandItemRead">
<Id>IsMainHeating-On</Id> <!-- required -->
<TapioMachineId>vjkz1807001001</TapioMachineId> <!-- required -->
<NodeId>ns=2;s=Framework.SoftKeys.003.Value</NodeId> <!-- required -->
</Command>
</Commands>
</Commanding>

add as many commands as required, then continue with the rest of the configuration as shown below:

            <Groups>
<!-- ... -->
</SourceBase>
</Servers>
</Source>
</Module>

Configure command types

It is possible to configure the following specific Command types:

CommandMethodCall

The CommandMethodCall command type contains:

ParameterTypeRequiredDefault valueDescription
IdStringyesthe identifier for the call, a unique id of this command within the current "SourceOpcUa" section
TapioMachineIdStringyesthe tapio machine id, for which this command being registered
MethodNodeIdStringyesnode id to identify the method on the opc ua server; if this is not specified in the configuration then the command is not executed and an error is returned!
ObjectNodeIdStringyesnode id of method containing folder node; if this is specified in the configuration and the IoT-Hub call also contains this value, then the command is not executed and an error is returned!
ArgumentsList of "Argument"nocan be configured and received from call
ResponseTimeOutstring (TimeSpan)no"00:05:00"overall timeout for scheduling jobs
ConnectionTimeOutstring (TimeSpan)no"00:00:15"timeout for the connection

Argument DataType contains:

  • Name (string; the name of the argument)
  • Value (string; the value of the argument; this has also a attribute of "valueType" which matches the supported values types from the JSON interface (see above))

You cannot overwrite argument values that are predefined in the CloudConnector configuration. If there is no values predefined for an argument, you can pass the value of it within the actual command call.

When you transfer a value in a command you must set the type of your command for example "commandType" : "itemWrite"

Available command types

CommandTypeDescription
methodCommand type to call a method. This type is required if your command contains at least one argument
itemReadCommand type to read a value.
itemWriteCommand type to write a value. This type is required if your command contains a value

CommandItemWrite

The CommandItemWrite command type contains:

ParameterTypeRequiredDescription
IdStringyesthe identifier for the call, a unique id of this command within the current "SourceOpcUa" section
TapioMachineIdStringyesthe tapio machine id, on which this command is being registered
NodeIdStringyesnode id to identify the method on the opc ua server; if this is not specified in the configuration then the command is not executed and an error is returned!
Value(Argument) Valuenothe value of the argument; can be configured and received from call, this has also a attribute of "valueType" which matches the supported values types from the JSON interface (see above) example: <Value type="UInt32">2</Value>

Example can be found in excerpt above.

CommandItemRead

The CommandItemRead command type contains:

ParameterTypeRequiredDescription
IdStringyesthe identifier for the call, a unique id of this command within the current "SourceOpcUa" section
TapioMachineIdStringyesthe tapio machine id, on which this command is being registered
NodeIdStringyesnode id to identify the method on the opc ua server; if this is not specified in the configuration then the command is not executed and an error is returned!

Example can be found in excerpt above.

The available commands (and the parameters required by each command) are depending on the manufacturer and the type of the machine.

For more information on this matter, please contact the manufacturer of the machine.

Execute command

Execute a command using the REST API requires you to execute:

  • A POST request to execute the command on the following end-point https://core.tapio.one/api/commanding.

A JWT Bearer token is required as authentication header and the MachineCommanding-Capability should be set, see Register tapio Application and -authentication for details. This function ensures that only one of the same command, e.g. EdgeHeating-On can be execute at the same time. Use the ResourceId https://tapiousers.onmicrosoft.com/CoreApi for the token request otherwise you get an Unauthorized.

The execution time of a command cannot be longer than 5 minutes. After this time span, a "timeout" error will occur.

Execute a new command

In the body of the POST request from above, the following JSON entity should be passed.

Use the ResourceId https://tapiousers.onmicrosoft.com/CoreApi for the token request otherwise you get an Unauthorized.

{
"tmid" : "the tapio machine id of the target machine",
"serverId": "the identification number of the server sending the command",
"id": "the name of the command to send"
}

As an example, the following command starts the heater, using a predefined command on the specified machine.

{
"tmid": "012345678901243",
"serverId": "Simu2",
"id": "EdgeHeater-On"
}

This call will return an http response, with return code 200 if the request was successful, as well as the following response body:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "200",
"commandResponse":
{
"statusCode": 0,
"outArguments":
{
"value":
{
"valueType": "Double",
"value": "1.1"
}
}
}
}
]

Additional command information

The response of a command execution, is a json array of command objects. You will receive an array as a response, because you're command could be executed on multiple machines.

PropertyDescription
cloudConnectorIdstring: id of the CloudConnector
statusstring: the status of the command, see list below
statusDescriptionstring: additional status information when job handling fails
commandResponseobject: the command response when available

Possible status values: 200, 400, 409, 429, 500 (has no relation to HTTP Status Codes!)

IoT hub status codeDescription
200Execution of this command was successful
400Execution of this command failed, because something went wrong on the machine's OPC UA server. Check the response
409Multiple CloudConnectors are responsible for one machine and execute the command but do not respond. See response for more information (example see below).
429The device is busy and can not execute multiple commands at the same time
500An error occurred by executing the command in the CloudConnector. Check the response

The "commandResponse" can contain different properties:

In case of an internal error. It could contains some more detail error information of the machine. The error information depends on the machine how detailed the information are.

...
"commandResponse":
{
"internalError":
{
"errorCode": 5,
"errorText": "Device is busy"
}
}
...

In case of successful read command, it returns the value and the type of the value. For "write"-commands it will only return the "statusCode".

...
"commandResponse":
{
"statusCode": 0,
"outArguments":
{
"value":
{
"valueType": "Double",
"value": "1.1"
}
}
}
...

In case of a conflict error, the response contains information which CloudConnector did not responded and the reason at least with an error code.

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "501",
"commandResponse": null
}
]

The status code in this response tells the call the responding CloudConnector send an information with 501 which means Not Implemented.

The table below describes the status codes which you can get by calling a command on a CloudConnector.

CloudConnector status codeDescription
200Execution of this command was successful (Can occur when 2 CloudConnectors are responsible for a command)
204The command was empty
400The command execution failed during communication with the OPC UA server, check the commandResponse for details
500An internal server error occurred while executing the command, check the commandResponse for details
501The called predefined command is not configured for the selected CloudConnector

Set connection-timeout and response-timeout

You can override the default response timeout for scheduling jobs and the connection timeout for each command.
The timeouts can be set independently. If no timeouts are set, the default values are used.

Be aware, that the connection timeout needs to be smaller than the response timeout. Also both values need to be set in a timerange from 00:00:05 - 00:05:00

Supported value types

The given types are supported as value types for arguments:

  • Int32
  • UInt32
  • Boolean
  • String
  • byte[] (base64 encoded string)
  • Double
  • Float

Write Command

Below is an example of a "write"-command, which changes the state of the edge heater to "on" using a predefined command configuration on the specified machine.

{
"tmid": "012345678901243",
"serverId": "Simu2",
"id": "EdgeHeater-On",
"commandType" : "itemWrite",
"inArguments":
{
"value":
{
"valueType": "Boolean",
"value": "true"
}
}
}

When the value to write is not pre-configured inside the config, it should be passed as an single value input parameter, see example (above).

The "inArguments" have the following format:

PropertyDescription
nameobject: name of the argument (for itemWrite this is always "value")
argumentArgument: argument with the valueType and value

The "argument" have the following format:

PropertyDescription
valueTypestring: valueType which matches the supported value types (see above Supported value types)
valuestring; the value of the argument

An example of a successful read command:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "200",
"commandResponse":
{
"statusCode": 0
}
}
]

For example this 'statusCode = 0' means that no error has occurred while executing the command.

Read Command

As an example the following command reads the state of the edge heater via a predefined command on the specified machine.

{
"tmid": "012345678901243",
"serverId": "Simu2",
"id": "IsEdgeHeater-On"
}

An example of a successful read command:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "200",
"commandResponse":
{
"statusCode": 0,
"outArguments":
{
"value":
{
"valueType": "Double",
"value": "1.1"
}
}
}
}
]

Method call with argument

As an example, the following command will execute a method which will change the drill of a machine. Therefore it needs to pass two parameters using a predefined command on the specified machine.

{
"tmid": "012345678901243",
"serverId": "Simu2",
"id" : "Change-Drill",
"commandType": "method",
"inArguments":
{
"Parameter1":
{
"valueType": "String",
"value": "countersunk drill"
},
"Parameter2":
{
"valueType": "Double",
"value": "1.4"
}
}
}

An example of a successful method command:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "200",
"commandResponse":
{
"statusCode": 0,
"outArguments":
{
"Parameter1":
{
"valueType": "String",
"value": "countersunk drill"
},
"YouThinkItsNice":
{
"valueType": "Double",
"value": "1.4"
}
}
}
}
]
Method call with merged argument

As an example the following command will execute a method which will change the drill using two parameters. One parameter value will be passed within the command, and the other parameter's value will be added through the CloudConnector configuration.

{
"tmid": "012345678901243",
"serverId": "Simu2",
"id" : "Change-Drill",
"commandType": "method",
"inArguments":
{
"Parameter1":
{
"valueType": "String",
"value": "override countersunk drill"
}
}
}

An example of a successful method command:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "200",
"commandResponse":
{
"statusCode": 0,
"outArguments":
{
"Parameter1":
{
"valueType": "String",
"value": "countersunk drill"
},
"YouThinkItsNice":
{
"valueType": "Double",
"value": "1.4"
}
}
}
}
]

When you try to overwrite the first parameter (in this example "Parameter1") an error will occur, because it is not allowed to override parameter values, which have a predefined value in the CloudConnector configuration.

CloudConnector is busy

When you try to execute the same command multiple times, before the execution of a previous command is finished, you will get an error with HTTP status code 429. This means "to many requests" for this machine.

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "400",
"commandResponse":
{
"internalError":
{
"errorCode": 5,
"errorText": "Device is busy"
}
}
}
]

Opc Ua server is not connected

An example error response, if the CloudConnector has no connection to the Opc UA server:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "400",
"commandResponse":
{
"internalError":
{
"errorCode": 5,
"errorText": "Opc Ua Server is not connected"
}
}
}
]

And last but not least, responses can vary based on the type of information read on the machine.

The following JSON snippets show the response types returned be the "Execute Command" end-point:

Predefined command is not found

This response occurs, if the called machine has not defined such a command in it's configuration.

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "400",
"commandResponse":
{
"internalError":
{
"errorCode": 6,
"errorText": "The [predefined Command id:] EdgeHeater2-OFF behind the [tmid:] 012345678901243 is not found"
}
}
}
]

Predefined command misconfigured

This response occurs, if a predefined command is misconfigured, for example the Node Id is not set.

[
{
"cloudConnectorId": "fenEqD-IRGoJbzCa7mGyzEcLGbiSKAYbgYY2t31aFZouL0ofRhZ2tlYtd6rD9s7h8XdoHuDBZiFomNN5cqLD1w",
"status": "400",
"commandResponse":
{
"internalError":
{
"errorCode": 2,
"errorText": "The method called is not supported. Invalid node id information for predefined command IsMainHeating-NoNodeId."
}
}
}
]

CloudConnector of machine has no connection to the tapio cloud

This error occurs, if the CloudConnector of a machine is not connected to the tapio system and cannot receive the command in time.

[
{
"cloudConnectorId": "JCk_1EBFef58bEoCiaBbD88DkxQ9HSkJ-lJVAhjf1wI_tIMFTiGZKwXfKUxMaqaLZhVx7rLKeHo3xqs7q9jNOw",
"status": "429",
"statusDescription": "Failed to start direct method call for device: JCk_1EBFef58bEoCiaBbD88DkxQ9HSkJ-lJVAhjf1wI_tIMFTiGZKwXfKUxMaqaLZhVx7rLKeHo3xqs7q9jNOw, message: Timed out waiting for device to connect.",
"commandResponse": null
}
]

Sample response without values

An example of a response without returned values.

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "400",
"commandResponse":
{
"statusCode":0
}
}
]

The parameter "statusCode" contains the status of the OPC UA Server where 0 indicates "success". The property "status" describe if the command was successful.

Sample response containing values

The following sample shows a response containing return values:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "200",
"commandResponse":
{
"statusCode": 0,
"outArguments":
{
"Arg01":
{
"valueType":"UInt32",
"value":"758568236"
},
"Name":
{
"valueType" : "String",
"value" : null
}
}
}
}
]

Sample response containing error information

Furthermore, a response could also contain information about errors the CloudConnector service is returning. The following sample shows a response containing detailed error information:

[
{
"cloudConnectorId": "fenddsD-IRGoJk.........LD1w",
"status": "400",
"commandResponse":
{
"internalError":
{
"errorCode": 3,
"errorText": "Invalid 'serverId' passed"
}
}
}
]