# Remote Methods
The Ability Egde framework allows you to specify the remote methods/commands that your module supports. This enables you to invoke some methods on the Edge remotely, using the Instance API of Ability Platform.
# Type Definition
First, you need to specify the methods that your module supports in its abb.ability.device information model. Here's an example:
{
"model": "abb.ability.device",
"typeId": "abb.mj.simpleEdge.module.device",
"version": "1.0.0",
"unique": [
"name"
],
"properties": {
...
},
"variables": {
...
},
"methods": {
"startTelemetry": {
"description": "Start sending variable data"
},
"createDevices": {
"description": "Create specified number of abb.mj.sensor.device instances",
"input": {
"count": {
"description": "Number of devices to create",
"dataType": "integer"
}
}
},
"uploadFile": {
"description": "Upload a file that already exists in local storage",
"input": {
"sourceFileName": {
"description": "Name of the file to be taken from local storage",
"dataType": "string"
},
"targetFileName": {
"description": "Name of the file to be created in the cloud",
"dataType": "string"
},
"removeOnComplete": {
"description": "Decides whether the source file should be deleted after its upload",
"dataType": "boolean"
}
}
}
},
"relatedModels": {
"abb.ability.configuration": {
"type": "abb.mj.simpleEdge.module.configuration@1",
"uniqueMapping": {
"name": "name"
}
}
}
}
The type above defines three methods:
startTelemetry
createDevices
uploadFile
Methods support inputs if necessary. In the type above, startTelemetry
is a
method without inputs. However, both createDevices
and uploadFile
support
multiple inputs.
# Payload Format
Whenever a method is invoked on the module (via Instance API), the module will
receive the message on the topic {topics_methods_in}/{method_name}/{requestId}
.
The value of topics_methods_in
should be read from the environment variables,
as explained here.
The format of the payload depends on the existence of inputs of a given method. If the method does not define any inputs, the payload will be just empty. However, if the method defines inputs, the payload will contain the inputs that the method has been invoked with. Look into the "Example" section of this article to see a sample of that.
To respond to a method invocation, send a message with a valid JSON or empty
body to the topic {topics_methods_out}/{status}/{requestId}
, where requestId
has to match the one in the request message, and status has to be an integer.
The payload of this message must be a valid JSON object.
If your module serves as a gateway/proxy for other devices, you will receive
their method invocations on the topic {topics_methods_in}/$proxy/{requestId}
,
and the payload will be in the following format:
{
"objectId": "target device object id",
"method": "target method name",
"input": {
payload as defined in the method definition of the device type, optional
}
}
Responses must be delivered via the same topic as for modules' methods.
# Methods with files
Methods may accept files as their input. Here's an example of a method definition that contains a "file" input:
"getFirmware": {
"description": "Commands the edge to download a given file with firmware binaries",
"input": {
"firmware": {
"description": "Firmware archive file to be downloaded",
"dataType": "file"
}
}
}
If the method's input contains one or more file data type properties, Edge Proxy
will take care of downloading the files and placing them in the volume
associated with the target module (under /files
of the module's container). A
module will receive a method request via a standard
{topics_methods_in}/{method_name}
topic after the download is complete. The
path to a newly-downloaded file will be included in the payload of an MQTT
message. The file's name will be "random" in the module's filesystem. It is the
module's responsibility to remove the file when it is no longer needed.
Here's an example of how it works. Let's assume that the edge module has the "getFirmware" method defined (as shown above). In order to invoke it, an HTTP request should look like this:
curl -X 'POST' \
'https://ABILITY-API/objects/3ae00385-eb4f-4f45-b08b-3cb9e53bebad/models/abb.ability.device/methods/getFirmware' \
-H 'accept: application/json' \
-H 'Authorization: Bearer ***ACCESS_TOKEN***' \
-H 'Content-Type: application/json' \
-d '{"input":{"firmware": "firmwarev2-4-3.tar.xz"}}'
TIP
We assume that the file "firmwarev2-4-3.tar.xz" had been uploaded to the Global Storage, prior to invoking the method.
The Edge module would receive a message like this:
Topic:
modules/simpledotnetmodule/methods/req/getFirmware/add8645e-d822-41c9-a163-310441b901bd
Payload:
{
"firmware": "3ae00385-eb4f-4f45-b08b-3cb9e53bebad_firmwareadd8645e-d822-41c9-a163-310441b901bd"
}
The module can access the file at
/files/3ae00385-eb4f-4f45-b08b-3cb9e53bebad_firmwareadd8645e-d822-41c9-a163-310441b901bd
.
As you can see, the original file name (as defined in the Global Storage) is
not delivered to the module. If the file's name is somehow valuable to the
module as it receives the file, consider adding more inputs to the method. As an
example, you could extend the "getFirmware" method like this:
"getFirmware": {
"description": "Commands the edge to download a given file with firmware binaries",
"input": {
"firmware": {
"description": "Firmware archive file to be downloaded",
"dataType": "file"
},
"firmwareVersion": {
"description": "Version of the firmware",
"dataType": "string"
}
}
}
Anytime you invoke this method, you would have to attach both the file ("firmware") and the metadata about it ("firmwareVersion" in this case).
# Example
Let's assume that our module defines the following method in its type definition:
...
"methods": {
"echo": {
"description": "Print some message to the stdout",
"input": {
"messageText": {
"description": "Message to print out",
"dataType": "string"
}
}
}
},
...
The method's name is "echo", and, according to the description, its job is to
print the messageText
. Pretty useless in the context of an Ability Edge
module, but let's continue with that example for learning purposes.
When our Edge device starts and our module is running, we might invoke the method using the Ability Platform's Instance API:
curl --location --request POST 'https://{instance-api-url}/v1/objects/4fd2de7c-0a11-4f50-8f66-b985a261df12/models/abb.ability.device/methods/echo' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJ0eXA...' \
--data-raw '{
"input": {
"messageText": "Hello World"
}
}'
The result on the Edge module side is the following message being received:
Topic:
modules/simpledotnetmodule/methods/req/echo/a383fb95-3c5e-41f3-9a34-0b95823a1080:
Payload:
{
"messageText": "Hello World"
}
The name of the method is present in the topic itself. The payload contains the inputs that have been set while invoking the POST request using Instance API. Now, it is up to the Edge module's program to decide what to do with that message.