Command
Introduction
The command micro service (often called the command and control micro service) enables the issuance of commands or actions to devices on behalf of:
- other micro services within EdgeX Foundry (for example, an edge analytics or rules engine micro service)
- other applications that may exist on the same system with EdgeX Foundry (for example, a management agent that needs to shutoff a sensor)
- To any external system that needs to command those devices (for example, a cloud-based application that determined the need to modify the settings on a collection of devices)
The command micro service exposes the commands in a common, normalized way to simplify communications with the devices. There are two types of commands that can be sent to a device.
- a GET command requests data from the device. This is often used to request the latest sensor reading from the device.
- SET commands request to take action or actuate the device or to set some configuration on the device.
In most cases, GET commands are simple requests for the latest sensor reading from the device. Therefore, the request is often parameter-less (requiring no parameters or body in the request). SET commands require a request body where the body provides a key/value pair array of values used as parameters in the request (i.e. {"additionalProp1": "string", "additionalProp2": "string"}
).
EdgeX 2.1
v2.1 supports a new value type, Object
, to present the structral value instead of encoding it as string for both SET and GET commands, for example, the SET command parameter might be {"Location": {"latitude": 39.67872546666667, "longitude": -104.97710646666667}}
.
The command micro service gets its knowledge about the devices from the metadata service. The command service always relays commands (GET or SET) to the devices through the device service. The command service never communicates directly to a device. Therefore, the command micro service is a proxy service for command or action requests from the north side of EdgeX (such as analytic or application services) to the protocol-specific device service and associated device.
While not currently part of its duties, the command service could provide a layer of protection around device. Additional security could be added that would not allow unwarranted interaction with the devices (via device service). The command service could also regulate the number of requests on a device do not overwhelm the device - perhaps even caching responses so as to avoid waking a device unless necessary.
Data Model
EdgeX 2.0
While the general concepts of core command's GET/PUT requests are the same, the core command request/response models has changed significantly in EdgeX 2.0. Consult the API documentation for details.
Data Dictionary
Property | Description |
---|---|
Id | uniquely identifies the device, a UUID for example |
Description | |
Name | Name for identifying a device |
Manufacturer | Manufacturer of the device |
Model | Model of the device |
Labels | Labels used to search for groups of profiles |
DeviceResources | deviceResource collection |
DeviceCommands | collect of deviceCommand |
Property | Description |
---|---|
DeviceName | reference to a device by name |
ProfileName | reference to a device profile by name |
CoreCommands | array of core commands |
Property | Description |
---|---|
Name | |
Get | bool indicating a get command |
Set | bool indicating a set command |
Path | |
Url | |
Parameters | array of core command parameters |
Property | Description |
---|---|
ResourceName | |
ValueType |
High Level Interaction Diagrams
The two following High Level Diagrams show:
- Issue a PUT command
- Get a list of devices and the available commands
Command PUT Request
Request for Devices and Available Commands
Configuration Properties
Please refer to the general Common Configuration documentation for configuration properties common to all services. Below are only the additional settings and sections that are not common to all EdgeX Services.
EdgeX 2.3
RequireMessageBus
and MessageQueue
configurations were added in EdgeX 2.3 for Commands via Messaging
Property | Default Value | Description |
---|---|---|
RequireMessageBus | true | Indicates whether to connect to internal message bus for Commands via messaging |
Property | Default Value | Description |
---|---|---|
Entries in the MessageQueue section of the configuration allow for connecting to a message bus |
Property | Default Value | Description |
---|---|---|
Type | redis |
Indicates the type of messaging library to use. Currently this is Redis by default. Refer to the go-mod-messaging module for more information. |
Protocol | redis |
Indicates the connectivity protocol to use when connecting to the bus. |
Host | localhost |
Indicates the host of the messaging broker, if applicable. |
Port | 6379 | Indicates the port to use when publishing a message. |
AuthMode | usernamepassword |
Auth Mode to connect to EdgeX MessageBUs. |
SecretName | redisdb |
Name of the secret in the Secret Store to find the MessageBus credentials. |
Property | Default Value | Description |
---|---|---|
Key-value mappings allow for publication and subscription to the internal message bus | ||
DeviceRequestTopicPrefix | edgex/device/command/request |
For publishing requests to the device service. <device-service>/<device-name>/<command-name>/<method> will be added to this publish topic prefix |
DeviceResponseTopic | edgex/device/command/response/# |
For subscribing to device service responses |
CommandRequestTopic | edgex/core/command/request/# |
For subscribing to internal command requests |
CommandResponseTopicPrefix | edgex/core/command/response |
For publishing responses back to internal service. /<device-name>/<command-name>/<method> will be added to this publish topic prefix |
QueryRequestTopic | edgex/core/commandquery/request/# |
For subscribing to internal command query requests |
QueryResponseTopic | edgex/core/commandquery/response |
For publishing command query responses back to internal service |
Property | Default Value | Description |
---|---|---|
Configuration and connection parameters used when Type is mqtt instead of redis |
||
ClientId | core-data |
Client ID used to put messages on the bus |
Qos | 0 | Quality of Service values are 0 (At most once), 1 (At least once) or 2 (Exactly once) |
KeepAlive | 10 | Period of time in seconds to keep the connection alive when there is no messages flowing (must be 2 or greater) |
Retained | false | Whether to retain messages |
AutoReconnect | true | Whether to reconnect to the message bus on connection loss |
ConnectTimeout | 5 | Message bus connection timeout in seconds |
SkipCertVerify | false | TLS configuration - Only used if Cert/Key file or Cert/Key PEMblock are specified |
Property | Default Value | Description |
---|---|---|
Enabled | false | Indicates whether to connect to external MQTT broker for the Commands via messaging |
Url | tcp://localhost:1883 |
Fully qualified URL to connect to the MQTT broker |
ClientId | core-data |
ClientId to connect to the broker with |
ConnectTimeout | 5s | Time duration indicating how long to wait before timing out broker connection, i.e "30s" |
AutoReconnect | true | Indicates whether or not to retry connection if disconnected |
KeepAlive | 10 | Seconds between client ping when no active data flowing to avoid client being disconnected. Must be greater then 2 |
QOS | 0 | Quality of Service 0 (At most once), 1 (At least once) or 2 (Exactly once) |
Retain | true | Retain setting for MQTT Connection |
SkipCertVerify | false | Indicates if the certificate verification should be skipped |
SecretPath | mqtt |
Name of the path in secret provider to retrieve your secrets. Must be non-blank. |
AuthMode | none |
Indicates what to use when connecting to the broker. Must be one of "none", "cacert" , "usernamepassword", "clientcert". If a CA Cert exists in the SecretPath then it will be used for all modes except "none". |
Property | Default Value | Description |
---|---|---|
Key-value mappings allow for publication and subscription to the external message bus | ||
CommandRequestTopic | edgex/command/request/# |
For subscribing to 3rd party command requests |
CommandResponseTopicPrefix | edgex/command/response |
For publishing responses back to 3rd party systems. /<device-name>/<command-name>/<method> will be added to this publish topic prefix |
QueryRequestTopic | edgex/commandquery/request/# |
For subscribing to 3rd party command query requests |
QueryResponseTopic | edgex/commandquery/response |
For publishing command query responses back to 3rd party systems |
Note
MessageQueue.External.Enabled
is working only if RequireMessageBus=true
because Commands via Messaging relies on internal message bus to relay the request to device services.
V2 Configuration Migration Guide
Refer to the Common Configuration Migration Guide for details on migrating the common configuration sections such as Service
.
Commands via Messaging
Edgex 2.3
Commands via Messaging is new in EdgeX 2.3
Introduction
Previously, communications from a 3rd party system (enterprise application, cloud application, etc.) to EdgeX in order to acuate a device or get the latest information from a sensor was only accomplished via REST. The 3rd party system makes a REST call of the command service which then relays a request to a device service also using REST. There was no built-in means to make a message-based request of EdgeX or the devices/sensors it manages.
From Levski release, core command service adds support for an external MQTT connection (in the same manner that app services provide an external MQTT connection), which will allow it to act as a bridge between the internal message bus (implemented via either MQTT or Redis Pub/Sub) and external MQTT message bus.
Core Command as Message Bus Bridge
The Core Command service will serve as the EdgeX entry point for external, commands via message bus requests to the south side.
3rd party systems should not be granted access to the EdgeX internal message bus. Therefore, in order to implement communications via message bus (specifically MQTT), the command service needs to take messages from the 3rd party or external MQTT topics and pass them internally onto the EdgeX internal message bus where they can eventually be routed to the device services and then on to the devices/sensors (southside).
In reverse, response messages from the southside will also be sent through the internal EdgeX message bus to the command service where they can then be bridged to the external MQTT topics and respond to the 3rd party system requester.
Message Structure
Since most message bus protocols lack a generic message header mechanism (as in HTTP), providing request/response metadata is accomplished by defining a MessageEnvelope
object associated with each request/response.
The message topic names act like the HTTP paths and methods in REST requests. That is, the topic names specify the device receiver of any command request as paths do in the HTTP requests.
Message Envelope
Below is an example of the MessageEnvelope
for command query request:
{
"ApiVersion": "v2",
"RequestId": "e6e8a2f4-eb14-4649-9e2b-175247911369",
"CorrelationID": "14a42ea6-c394-41c3-8bcd-a29b9f5e6835",
"ContentType": "application/json",
"QueryParams": {
"offset": "0",
"limit": "10"
}
}
Below is an example of the MessageEnvelope
of command query response:
{
"ApiVersion":"v2",
"RequestID":"e6e8a2f4-eb14-4649-9e2b-175247911369",
"CorrelationID":"14a42ea6-c394-41c3-8bcd-a29b9f5e6835",
"ErrorCode":0,
"Payload":"...",
"ContentType":"application/json"
}
The messages for formatted requests and responses are sharing a common base structure.
The outermost JSON object represents the message envelope, which is used to convey metadata about request/response including ApiVersion
, RequestID
, CorrelationID
...etc.
The Payload
field contains the base64-encoded response body.
The ErrorCode
field provides the indication of error.
The ErrorCode
will be 0 (no error) or 1 (indicating error) as the two enums for error conditions.
When there is an error (with ErrorCode
set to 1), then the payload contains a message string indicating more information about the error.
When there is no error (errorCode 0) then there is no message string in the payload.
Command Query
Core Command service subscribes to the QueryRequestTopic
and publishes the response to QueryResponseTopic
defined in the configuration file.
After receiving the request, Core Command service will try to parse the <device-name>
from request topic level.
The 3rd party system or application must publish command query requests messages and subscribe to responses from the same topics.
Below is the default topic naming used by Core Command:
- Subscribing command query request topic:
edgex/commandquery/request/#
- Publishing command query response topic:
edgex/commandquery/response
The last topic level in request topic must be either all
or the <device-name>
to query for.
Query by Device Name
Example of querying device core commands by device name via messaging:
-
Send query request message to external MQTT broker on topic
edgex/commandquery/request/Random-Boolean-Device
:{ "ApiVersion": "v2", "ContentType": "application/json", "CorrelationID": "14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "RequestId": "e6e8a2f4-eb14-4649-9e2b-175247911369" }
-
Receive query response message from external MQTT broker on topic
edgex/commandquery/response
:{ "ReceivedTopic":"", "CorrelationID":"14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "ApiVersion":"v2", "RequestID":"e6e8a2f4-eb14-4649-9e2b-175247911369", "ErrorCode":0, "Payload":"eyJhcGlWZXJzaW9uIjoidjIiLCJyZXF1ZXN0SWQiOiJlNmU4YTJmNC1lYjE0LTQ2NDktOWUyYi0xNzUyNDc5MTEzNjkiLCJzdGF0dXNDb2RlIjoyMDAsImRldmljZUNvcmVDb21tYW5kIjp7ImRldmljZU5hbWUiOiJSYW5kb20tQm9vbGVhbi1EZXZpY2UiLCJwcm9maWxlTmFtZSI6IlJhbmRvbS1Cb29sZWFuLURldmljZSIsImNvcmVDb21tYW5kcyI6W3sibmFtZSI6IldyaXRlQm9vbFZhbHVlIiwic2V0Ijp0cnVlLCJwYXRoIjoiL2FwaS92Mi9kZXZpY2UvbmFtZS9SYW5kb20tQm9vbGVhbi1EZXZpY2UvV3JpdGVCb29sVmFsdWUiLCJ1cmwiOiJodHRwOi8vZWRnZXgtY29yZS1jb21tYW5kOjU5ODgyIiwicGFyYW1ldGVycyI6W3sicmVzb3VyY2VOYW1lIjoiQm9vbCIsInZhbHVlVHlwZSI6IkJvb2wifSx7InJlc291cmNlTmFtZSI6IkVuYWJsZVJhbmRvbWl6YXRpb25fQm9vbCIsInZhbHVlVHlwZSI6IkJvb2wifV19LHsibmFtZSI6IldyaXRlQm9vbEFycmF5VmFsdWUiLCJzZXQiOnRydWUsInBhdGgiOiIvYXBpL3YyL2RldmljZS9uYW1lL1JhbmRvbS1Cb29sZWFuLURldmljZS9Xcml0ZUJvb2xBcnJheVZhbHVlIiwidXJsIjoiaHR0cDovL2VkZ2V4LWNvcmUtY29tbWFuZDo1OTg4MiIsInBhcmFtZXRlcnMiOlt7InJlc291cmNlTmFtZSI6IkJvb2xBcnJheSIsInZhbHVlVHlwZSI6IkJvb2xBcnJheSJ9LHsicmVzb3VyY2VOYW1lIjoiRW5hYmxlUmFuZG9taXphdGlvbl9Cb29sQXJyYXkiLCJ2YWx1ZVR5cGUiOiJCb29sIn1dfSx7Im5hbWUiOiJCb29sIiwiZ2V0Ijp0cnVlLCJzZXQiOnRydWUsInBhdGgiOiIvYXBpL3YyL2RldmljZS9uYW1lL1JhbmRvbS1Cb29sZWFuLURldmljZS9Cb29sIiwidXJsIjoiaHR0cDovL2VkZ2V4LWNvcmUtY29tbWFuZDo1OTg4MiIsInBhcmFtZXRlcnMiOlt7InJlc291cmNlTmFtZSI6IkJvb2wiLCJ2YWx1ZVR5cGUiOiJCb29sIn1dfSx7Im5hbWUiOiJCb29sQXJyYXkiLCJnZXQiOnRydWUsInNldCI6dHJ1ZSwicGF0aCI6Ii9hcGkvdjIvZGV2aWNlL25hbWUvUmFuZG9tLUJvb2xlYW4tRGV2aWNlL0Jvb2xBcnJheSIsInVybCI6Imh0dHA6Ly9lZGdleC1jb3JlLWNvbW1hbmQ6NTk4ODIiLCJwYXJhbWV0ZXJzIjpbeyJyZXNvdXJjZU5hbWUiOiJCb29sQXJyYXkiLCJ2YWx1ZVR5cGUiOiJCb29sQXJyYXkifV19XX19", "ContentType":"application/json", "QueryParams":{} }
Base64-decoding the Payload:
{
"apiVersion":"v2",
"requestId":"e6e8a2f4-eb14-4649-9e2b-175247911369",
"statusCode":200,
"deviceCoreCommand":{
"deviceName":"Random-Boolean-Device",
"profileName":"Random-Boolean-Device",
"coreCommands":[
{
"name":"WriteBoolValue",
"set":true,
"path":"/api/v2/device/name/Random-Boolean-Device/WriteBoolValue",
"url":"http://edgex-core-command:59882",
"parameters":[
{"resourceName":"Bool", "valueType":"Bool"},
{"resourceName":"EnableRandomization_Bool","valueType":"Bool"}
]
},
{
"name":"WriteBoolArrayValue",
"set":true,
"path":"/api/v2/device/name/Random-Boolean-Device/WriteBoolArrayValue",
"url":"http://edgex-core-command:59882",
"parameters":[
{"resourceName":"BoolArray","valueType":"BoolArray"},
{"resourceName":"EnableRandomization_BoolArray","valueType":"Bool"}
]
},
{
"name":"Bool",
"get":true,
"set":true,
"path":"/api/v2/device/name/Random-Boolean-Device/Bool",
"url":"http://edgex-core-command:59882",
"parameters":[
{"resourceName":"Bool","valueType":"Bool"}
]
},
{
"name":"BoolArray",
"get":true,
"set":true,
"path":"/api/v2/device/name/Random-Boolean-Device/BoolArray",
"url":"http://edgex-core-command:59882",
"parameters":[
{"resourceName":"BoolArray","valueType":"BoolArray"}
]
}
]
}
}
Query All
Example of querying all device core commands via messaging:
-
Send query request message to external MQTT broker on topic
edgex/commandquery/request/all
:{ "ApiVersion": "v2", "ContentType": "application/json", "CorrelationID": "14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "RequestId": "e6e8a2f4-eb14-4649-9e2b-175247911369", "QueryParams": { "offset": "0", "limit": "5" } }
-
Receive query response message from external MQTT broker on topic
edgex/commandquery/response
:{ "ApiVersion":"v2", "ContentType":"application/json", "CorrelationID":"14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "RequestID":"e6e8a2f4-eb14-4649-9e2b-175247911369", "ErrorCode":0, "Payload":"..." }
Command Request
Core Command service subscribes to the CommandRequestTopic
defined in the configuration file.
After receiving the request, Core Command service will try to parse <device-name>
<command-name>
and <method>
from request topic level,
and send the response back with <device-name>
, <command-name>
and <method>
appended to CommandResponseTopicPrefix
defined in the configuration file.
The 3rd party system or application must publish command requests messages and subscribe to responses from the same topics.
Below is the default topic naming used by Core Command:
- Subscribing command request topic:
edgex/command/request/#
- Publishing command response topic:
edgex/command/response/<device-name>/<command-name>/<method>
The last topic level (<method>
) in request topic must be either get
or set
.
Get Command
Example of making get command request via messaging:
- Send command request message to external MQTT broker on topic
edgex/command/request/Random-Boolean-Device/Bool/get
:{ "ApiVersion": "v2", "ContentType": "application/json", "CorrelationID": "14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "RequestId": "e6e8a2f4-eb14-4649-9e2b-175247911369", "QueryParams": { "ds-pushevent": "no", "ds-returnevent": "yes" } }
- Receive command response message from external MQTT broker on topic
edgex/commandquery/response/#
:{ "ReceivedTopic":"edgex/device/command/response/device-virtual/Random-Boolean-Device/Bool/get", "CorrelationID":"14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "ApiVersion":"v2", "RequestID":"e6e8a2f4-eb14-4649-9e2b-175247911369", "ErrorCode":0, "Payload":"eyJhcGlWZXJzaW9uIjoidjIiLCJyZXF1ZXN0SWQiOiJlNmU4YTJmNC1lYjE0LTQ2NDktOWUyYi0xNzUyNDc5MTEzNjkiLCJzdGF0dXNDb2RlIjoyMDAsImV2ZW50Ijp7ImFwaVZlcnNpb24iOiJ2MiIsImlkIjoiM2JiMDBlODYtMTZkZi00NTk1LWIwMWEtMWFhNTM2ZTVjMTM5IiwiZGV2aWNlTmFtZSI6IlJhbmRvbS1Cb29sZWFuLURldmljZSIsInByb2ZpbGVOYW1lIjoiUmFuZG9tLUJvb2xlYW4tRGV2aWNlIiwic291cmNlTmFtZSI6IkJvb2wiLCJvcmlnaW4iOjE2NjY1OTE2OTk4NjEwNzcwNzYsInJlYWRpbmdzIjpbeyJpZCI6IjFhMmM5NTNkLWJmODctNDhkZi05M2U3LTVhOGUwOWRlNDIwYiIsIm9yaWdpbiI6MTY2NjU5MTY5OTg2MTA3NzA3NiwiZGV2aWNlTmFtZSI6IlJhbmRvbS1Cb29sZWFuLURldmljZSIsInJlc291cmNlTmFtZSI6IkJvb2wiLCJwcm9maWxlTmFtZSI6IlJhbmRvbS1Cb29sZWFuLURldmljZSIsInZhbHVlVHlwZSI6IkJvb2wiLCJ2YWx1ZSI6ImZhbHNlIn1dfX0=", "ContentType":"application/json", "QueryParams":{} }
Base64-decoding the Payload:
{
"apiVersion":"v2",
"requestId":"e6e8a2f4-eb14-4649-9e2b-175247911369",
"statusCode":200,
"event":{
"apiVersion":"v2",
"id":"3bb00e86-16df-4595-b01a-1aa536e5c139",
"deviceName":"Random-Boolean-Device",
"profileName":"Random-Boolean-Device",
"sourceName":"Bool",
"origin":1666591699861077076,
"readings":[
{
"id":"1a2c953d-bf87-48df-93e7-5a8e09de420b",
"origin":1666591699861077076,
"deviceName":"Random-Boolean-Device",
"resourceName":"Bool",
"profileName":"Random-Boolean-Device",
"valueType":"Bool",
"value":"false"
}
]
}
}
Set Command
Example of making put command request via messaging:
- Send command request message to external MQTT broker on topic
edgex/command/request/Random-Boolean-Device/WriteBoolValue/set
:{ "ApiVersion": "v2", "ContentType": "application/json", "CorrelationID": "14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "RequestId": "e6e8a2f4-eb14-4649-9e2b-175247911369", "Payload": "eyJCb29sIjogImZhbHNlIn0=" }
The payload is the base64-encoding json struct:
{"Bool": "false"}
- Receive command response message from external MQTT broker on topic
edgex/command/response/#
{ "ReceivedTopic":"edgex/device/command/response/device-virtual/Random-Boolean-Device/Bool/set", "CorrelationID":"14a42ea6-c394-41c3-8bcd-a29b9f5e6835", "ApiVersion":"v2", "RequestID":"e6e8a2f4-eb14-4649-9e2b-175247911369", "ErrorCode":0, "Payload":null, "ContentType":"application/json", "QueryParams":{} }
Note
There are some cases that Core Command service will be unable to publish the response correctly, for example:
- Response topic is not specified in configuration file
- Failed to JSON-decoding the request MessageEnvelope
- Failed to parse either <device-name>
, <command-name>
or <method>