Using Eclipse Hono's Command&Control with Eclipse Ditto
With version 0.8.0 Eclipse Ditto can now interact with Eclipse Hono using the “Command & Control” feature. It is possible to send a Thing (or Feature) message at the Ditto Message API, which is then forwarded to Hono as a command message. Hono routes the message to the device, which in turn can send a response to the command including a status, telling if the command was successfully processed or not. This response is routed back via Hono to the Ditto Message API.
In this example we connect the Ditto sandbox and the Hono sandbox to send a message (3) to a simulated device via the Ditto Messages API. The device receives the command from the Hono HTTP Adapter and responds with a message (4) that is routed back to the caller at the Ditto Message API (5). For the sake of simplicity we use simple curl commands both for the Ditto and Hono HTTP APIs.
The following steps are covered in this example:
- Setup a connection between Eclipse Ditto and Hono sandboxes
- Signal availability of the device
- Send a Ditto message
- Device receives command and sends command response
- Caller receives response at Ditto Message API
Prerequisites: A Ditto digital twin and a Hono device
The creation of a Hono device and Ditto digital twin has already been covered in the blog post Connecting Eclipse Ditto to Eclipse Hono. For brevity we will just list the required commands to create a twin/device here. For a detailed explanation of the steps please refer to the previous post.
Create Hono device
# setup a tenant
$ curl -X POST -i -H 'Content-Type: application/json' -d '{"tenant-id": "org.eclipse.ditto"}' https://hono.eclipseprojects.io:28080/tenant
# create a device
$ curl -X POST -i -H 'Content-Type: application/json' -d '{"device-id": "org.eclipse.ditto:teapot"}' https://hono.eclipseprojects.io:28080/registration/org.eclipse.ditto
# add device credentials
$ PWD_HASH=$(echo -n 'teapot' | openssl dgst -binary -sha512 | base64 -w 0)
$ curl -X POST -i -H 'Content-Type: application/json' -d '{
"device-id": "org.eclipse.ditto:teapot",
"type": "hashed-password",
"auth-id": "teapot",
"secrets": [{
"hash-function" : "sha-512",
"pwd-hash": "'$PWD_HASH'"
}]
}' https://hono.eclipseprojects.io:28080/credentials/org.eclipse.ditto
Create Ditto policy for digital twin
# create policy in Ditto
$ curl -X PUT -i -u demo5:demo -H 'Content-Type: application/json' -d '{
"policyId": "org.eclipse.ditto:teapot-policy",
"entries": {
"DEMO": {
"subjects": {
"nginx:demo5": {
"type": "basic auth user and user used in connection's authorizationContext"
}
},
"resources": {
"thing:/": {
"grant": ["READ", "WRITE"],
"revoke": []
},
"policy:/": {
"grant": ["READ", "WRITE"],
"revoke": []
},
"message:/": {
"grant": ["READ", "WRITE"],
"revoke": []
}
}
}
}
}' https://ditto.eclipseprojects.io/api/2/policies/org.eclipse.ditto:teapot-policy
Create Ditto digital twin
# create thing in Ditto
$ curl -X PUT -i -u demo5:demo -H 'Content-Type: application/json' -d '{
"policyId": "org.eclipse.ditto:teapot-policy",
"features": {
"water": {
"properties": {
"temperature": 20
}
}
}
}' https://ditto.eclipseprojects.io/api/2/things/org.eclipse.ditto:teapot
Setup a connection for Command & Control
In order to forward Ditto Messages to the device as a Hono command we first need to setup and configure a
connection between Eclipse Ditto and Eclipse Hono that is prepared for
Command & Control messages. According to the
Hono documentation
the connection must contain a target with the address control/<tenant-id>/<device-id>
and a source with the address control/<tenant-id>/<reply-identifier>
. The reply-identifier
can be
chosen arbitrarily, but must be set as the reply-to
header of a command exactly as defined in the connection:
curl -X POST -i -u devops:devopsPw1! \
-H 'Content-Type: application/json' \
-d '{
"targetActorSelection": "/system/sharding/connection",
"headers": {
"aggregate": false
},
"piggybackCommand": {
"type": "connectivity.commands:createConnection",
"connection": {
"id": "command-and-control-connection",
"connectionType": "amqp-10",
"connectionStatus": "open",
"uri": "amqp://consumer%40HONO:verysecret@hono.eclipse.org:15672",
"failoverEnabled": true,
"sources": [{
"addresses": [
"control/org.eclipse.ditto/replies"
],
"authorizationContext": [
"nginx:demo5"
],
"headerMapping": {
"correlation-id": "{{ header:correlation-id }}",
"status": "{{ header:status }}",
"content-type": "{{ header:content-type }}"
}
}
],
"targets": [{
"address": "control/org.eclipse.ditto/{{ thing:name }}",
"authorizationContext": [
"nginx:demo5"
],
"topics":["_/_/things/live/messages"],
"headerMapping": {
"message-id": "{{ header:correlation-id }}",
"subject": "{{ topic:subject }}",
"content-type": "application/vnd.eclipse.ditto+json",
"reply-to": "control/org.eclipse.ditto/replies"
}
}
]
}
}
}' \
https://ditto.eclipseprojects.io/devops/piggyback/connectivity?timeout=10s
As described in the
Hono API description
a command message has three mandatory properties: correlation-id
, subject
and reply-to
, these are defined in the
target header mapping of the connection.
The source header mapping defines a mapping for correlation-id
and status
to internal headers, they are required
to properly map the Hono command response to a Ditto message response.
Signal availability of device
As we are using the Hono HTTP Adapter to connect our device, send telemetry and receive commands, the designated way
is therefor to signal readiness to receive a command by specifying the hono-ttd
parameter on an arbitrary event (for
detailed description please consult the
[Hono HTTP Adapter] (https://www.eclipse.org/hono/)
guide).
curl -X POST -i -u teapot@org.eclipse.ditto:teapot -H 'hono-ttd: 60' -H 'Content-Type: application/json' \
-d '{
"topic": "org.eclipse.ditto/teapot/things/twin/commands/modify",
"path": "/features/water/properties/temperature",
"value": 23
}' \
https://hono.eclipseprojects.io:8080/telemetry
The request is now open to receive a command for 60 seconds before it is terminated.
Send a Ditto message
Now we can use the Ditto Messages API to send a message to the device waiting for a command:
curl -i -X POST 'https://ditto.eclipseprojects.io/api/2/things/org.eclipse.ditto:teapot/inbox/messages/brew?timeout=60' \
-u demo5:demo \
-H 'x-correlation-id: command-and-control' \
-d '{"targetTemperature":85}'
Device receives the command
The message is forwarded to Hono as configured in the connection and finally terminates the pending request we opened
before with a status code of 200 OK
:
HTTP/1.1 200 OK
hono-command: brew
hono-cmd-req-id: 013command-and-controlreplies
Content-Type: application/octet-stream
Content-Length: 17
Connection: Keep-Alive
Hono adds two headers besides the standard HTTP headers: hono-command
and hono-cmd-req-id
.
hono-command
contains the subject of the message and hono-cmd-req-id
identifies the messages and is used to
correlate the request and the response we are now going to send.
Device sends a command response
We use the header value of hono-cmd-req-id
to construct the response address:
https://hono.eclipseprojects.io:8080/control/res/013command-and-controlreplies
Another curl command completes the roundtrip with a response from the simulated device:
curl -i -X POST -u teapot@org.eclipse.ditto:teapot \
-H 'Content-Type: application/json' \
-H 'hono-cmd-status: 200' \
-d '{
"topic": "org.eclipse.ditto/teapot/things/live/messages/brew",
"headers": {
"content-type": "application/json",
"correlation-id": "command-and-control"
},
"path": "/inbox/messages/brew",
"value": { "eta": 56},
"status": 200
}' \
https://hono.eclipseprojects.io:8080/control/res/013command-and-controlreplies
Message response is received at Ditto Message API
And finally we receive the command response at the Ditto Message API where we sent the original message:
HTTP/1.1 200 OK
correlation-id: command-and-control
message-id: command-and-control
status: 200
Content-Type: application/json
Content-Length: 10
{"eta":56}
Alternative: Receive command and send response via MQTT
Alternatively we can also receive the command by subscribing to the MQTT topic control/+/+/req/#
at the
Hono MQTT Adapter:
$ mosquitto_sub -d -h hono.eclipse.org -p 8883 -v -u 'teapot@org.eclipse.ditto' -P teapot -t 'control/+/+/req/#'
And also publish the command response on the MQTT topic control///res/013command-and-controlreplies/200
:
mosquitto_pub -d -h hono.eclipse.org -p 8883 -u 'teapot@org.eclipse.ditto' -P teapot \
-t control///res/013command-and-controlreplies/200 \
-m '{
"topic": "org.eclipse.ditto/teapot/things/live/messages/brew",
"headers": {
"content-type": "application/json",
"correlation-id": "command-and-control"
},
"path": "/inbox/messages/brew",
"value": {
"eta": 58
},
"status": 200
}'
If you have any wishes, improvements, are missing something or just want to get in touch with us, you can use one of our feedback channels.
–
The Eclipse Ditto team