|
Posted
about 7 years
ago
Today the Eclipse Ditto team proudly presents its first release
0.8.0.
Please have a look at the 0.8.0 release notes for a more detailled information on the release.
The main changes and new features since the latest milestone 0.8.0-M3 are:
... [More]
Support Eclipse Hono’s command&control in Ditto connectivity
several smaller bugfixes
Artifacts
The new Java artifacts have been published at the Eclipse Maven repository
as well as Maven central.
The Docker images have been pushed to Docker Hub:
eclipse/ditto-policies
eclipse/ditto-things
eclipse/ditto-things-search
eclipse/ditto-gateway
eclipse/ditto-connectivity
eclipse/ditto-concierge
–
The Eclipse Ditto team
[Less]
|
|
Posted
about 7 years
ago
Today the Eclipse Ditto team proudly presents its first release
0.8.0.
Please have a look at the 0.8.0 release notes for a more detailed information on the release.
The main changes and new features since the latest milestone 0.8.0-M3 are:
... [More]
Support Eclipse Hono’s command&control in Ditto connectivity
several smaller bugfixes
Artifacts
The new Java artifacts have been published at the Eclipse Maven repository
as well as Maven central.
The Docker images have been pushed to Docker Hub:
eclipse/ditto-policies
eclipse/ditto-things
eclipse/ditto-things-search
eclipse/ditto-gateway
eclipse/ditto-connectivity
eclipse/ditto-concierge
–
The Eclipse Ditto team
[Less]
|
|
Posted
about 7 years
ago
Preparing the upcoming first release 0.8.0 of
Eclipse Ditto, this milestone is a last checkpoint to ensure that the release will be performed smoothly.
Therefore, this milestone release primarily focuses on stabilization.
Have a look at the
... [More]
Milestone 0.8.0-M3 release notes for what changed in detail.
Warning: If you want to upgrade an existing Ditto installation, you’ll have to execute a small
database migration - see release notes.
The main changes and new features are
speed up of search index creation
applying enforcement of messages received via connections (e.g. from Eclipse Hono)
copying already existing policies when creating things
Artifacts
The new Java artifacts have been published at the Eclipse Maven repository
as well as Maven central.
The Docker images have been pushed to Docker Hub:
eclipse/ditto-policies
eclipse/ditto-things
eclipse/ditto-things-search
eclipse/ditto-gateway
eclipse/ditto-connectivity
eclipse/ditto-concierge
–
The Eclipse Ditto team
[Less]
|
|
Posted
about 7 years
ago
Eclipse Ditto can now connect to MQTT 3.1.1 brokers.
Perfect timing to happily welcome a new colleague to our team behind Eclipse Ditto: David.
In order to get familiar with Ditto and the development with digital twins, David was assigned with one
... [More]
of his first
tasks to get his hands on one of our newest features, MQTT connectivity
which was released recently with milestone 0.8.0-M2.
On his journey into digital twin land he made a great example with an ESP8266 powered board connected via an MQTT broker
to Ditto and published it to the
Eclipse Ditto examples repository:
This example is about how to communicate between device and solution in a two way pattern through Ditto using MQTT.
This means we will add a policy, a thing and a MQTT connection to Ditto.
When Ditto ist set up and working, we will create real world device (“octopus board”) and connect it to it’s
digital twin via MQTT.
At the end, we will create a basic frontend webapp.
The webapp will automatically connect to Ditto when you type in your credentials, automatically pull your things
and show them in a list.
You can create, modify and delete devices in the webapp and if there is a real world device connected to the thing
in the list, you can send it a command message to control any feature on it.
The list of things will always be up-to-date when you listen to server-sent-events, which you can activate easily
with pressing a button.
Source: https://github.com/eclipse/ditto-examples
We will use an Octopus-board with an ESP8266 on it. It has several sensors built in, but for simplicity we will
just use it’s temperature and altitude sensor.
To show the functionality of Eclipse Ditto messages, we will switch on/off a LED on the Octopus-board through it.
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
[Less]
|
|
Posted
about 7 years
ago
Brace yourself, Eclipse Ditto is preparing for its
first release 0.8.0. We are happy to announce our next
milestone towards that goal.
Have a look at the Milestone 0.8.0-M2 release notes for what changed in detail.
The main changes and new
... [More]
features are
enforcement of max. entity size of twins and messages
added MQTT support connecting to MQTT 3.1.1 brokers
subscribing to changes based on filters
conditional requests at all APIs
Artifacts
Unfortunately, we had some problems during the milestone release build causing that the released artifacts have version
0.8.0-M2b instead of 0.8.0-M2.
The new Java artifacts have been published at the Eclipse Maven repository
as well as Maven central.
The Docker images have been pushed to Docker Hub:
eclipse/ditto-policies
eclipse/ditto-things
eclipse/ditto-things-search
eclipse/ditto-gateway
eclipse/ditto-connectivity
eclipse/ditto-concierge
–
The Eclipse Ditto team
[Less]
|
|
Posted
about 7 years
ago
The connectivity service supercharged Ditto’s flexibility in integrating with other services.
It’s such a great feature to let the other connected services know about thing updates and property changes.
Even the direct exchange with real-world assets
... [More]
became more flexible through the multi-protocol support.
But with a steady increase in connected devices, those messages easily sum up to a huge number.
Note: In order to simplify a little, we here use the term message as synonym for both Ditto
signals and messages.
Also, not every consuming application needs to know everything that’s going on.
In fact, the only use case that requires processing of every message is logging.
Therefore most of the times an application waits for a specific message to trigger a specific action.
So all other messages are discarded unused.
This adds a lot of unnecessary overhead both to the message transport capabilities and the processing of messages at the receiving end.
But what if you could avoid receiving those messages at all.
Well, you can!
This is exactly what selective push notifications do:
Configurable message filters that are applied to Ditto’s publishing connection before anything goes on the line.
They can help you with a lot of problems in a bunch of scenarios:
Bandwidth limitations: The amount of occurring events is too large and/or frequent to be delivered via the available channels. With selective message filters, you can mute the noise in your event stream.
Information hiding: Let consuming services only know what they need to know. Message filters allow you to control all published content in great detail.
Specialized notifications: A specific event filter can be used to set a value thresholds or a status-change trigger. This removes the burden of implementing filter logic on the application side.
Event routing: Create multiple connections with Ditto’s connectivity service and route your events through those aligned with your requirements. All by specifying appropriate filters for your connection targets.
The following diagram visualizes this context:
With the upcoming Ditto release 0.8.0-M2, those filters are available for the following endpoints:
WebSocket
Server-Sent Events (SSE)
All supported connectivity protocols (AMQP 0.9.1, AMQP 1.0 / Eclipse Hono, MQTT)
You can use a basic namespace filter on the following topics:
Twin events
Live events
Live messages
Live commands
This filter is a comma-separated list of selected namespaces. It only allows messages related to one of the given namespaces.
Furthermore, there is an additional RQL filter for an advanced description of twin and live events.
Powered by the mighty syntax of Ditto’s search API it allows configuring the selected events in the same manner as you search for things.
Check out the documentation for more information on options and configuration.
A simple example
Imagine you have a flat with multiple environmental sensors: Some measure temperature, some humidity and some both.
This information can be useful for different applications.
In our case, a smart thermostat uses the sensor data to control the indoor climate and there is also a fire alarm installed that detects fires by abnormal high measured temperatures
The following figure displays this setting:
So let’s start with the prerequisites. You need:
A running Ditto instance with a valid user (You can follow our Hello World example to create one). This example uses dittos default user on a locally running instance.
A tool for executing HTTP requests (e.g. Ditto’s Swagger API, cURL, Postman). We use this to create our twins and simulate the sensors.
A modern browser supporting WebSockets. This example uses websocket.org as a websocket client. The site will tell you if your browser supports the WebSocket protocol. We will mock our applications this way.
The digital twins
First we configure our sensors digital twins:
A temperature sensor
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'{
"features": {
"environmentSensor": {
"properties": {
"temperature": 0.0
}
}
}
}' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3ATemperatureSensor'
A humidity sensor
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'{
"features": {
"environmentSensor": {
"properties": {
"humidity": 0
}
}
}
}' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3AHumiditySensor'
A combined temperature and humidity sensor
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'{
"features": {
"environmentSensor": {
"properties": {
"temperature": 0.0,
"humidity": 0
}
}
}
}' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3ATemperatureAndHumiditySensor'
And finally, a teapot
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'{}' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3ATeapot'
Mocking the consuming applications
Open your browser on https://websocket.org/echo.html.
This site allows you to connect with any WebSocket endpoint and supports simple sending and receiving of messages. The interface is shown below:
Enter Ditto’s WebSocket endpoint with user credentials ws://ditto:ditto@localhost:8080/ws/2 and hit the Connect button.
The log output should confirm the action by printing a simple CONNECTED.
This means the socket is open and you’re able to receive messages from Ditto.
But first, you should let Ditto know in what kind of messages you’re interested.
This interest differs for both of the example applications:
The thermostat app only needs to know every humidity and temperature report so you can define a filter for change events on twins having those properties:
START-SEND-EVENTS?filter=or(exists(features/environmentSensor/properties/temperature),exists(features/environmentSensor/properties/humidity))
Paste it into the Message input and use the Send button to post it. Ditto should acknowledge with a START-SEND-EVENTS:ACK.
That’s it for our thermostat app, let’s proceed to the fire alarm.
Open https://websocket.org/echo.html again in a separate tab and repeat the connection process.
But instead of consuming all temperature and humidity reports, we only want to be notified when a specific temperature threshold is exceeded.
90°C seems to be a solid value for this:
START-SEND-EVENTS?filter=gt(features/environmentSensor/properties/temperature,90)
After receiving Ditto’s acknowledgment, you’re done with the configuration.
Report mocked sensor values to Ditto
Use Ditto’s HTTP API to send mocked data on behalf of our sensors. First report a new humidity value for the humidity sensor:
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'55' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3AHumiditySensor/features/environmentSensor/properties/humidity'
Now check both websocket.org tabs. The thermostat tab should have received an event with the reported value while nothing happened in the alarm tab.
Continue with some temperature data from another sensor:
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'23' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3ATemperatureAndHumiditySensor/features/environmentSensor/properties/temperature'
The value change should be reported to the thermostat, but still no events for the alarm tab.
Finally it’s time to start a fire. Report a very high temperature for the third sensor:
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'120' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3ATemperatureSensor/features/environmentSensor/properties/temperature'
Now both applications should have received the reported data, and the fire alarm can use this event to (virtually) trigger its bell.
But what about the teapot? Let him declare his identity by setting a personal message:
curl -X PUT -u 'ditto:ditto' --header 'Content-Type: application/json' -d \
'{
"properties": {
"message": "I'\''m a teapot"
}
}' \
'http://localhost:8080/api/2/things/org.eclipse.ditto%3ATeapot/features/status'
Unfortunately, no one cares and this no one is notified about that change.
We do hope that you care about this feature, we think it’s really awesome.
–
The Eclipse Ditto team
[Less]
|
|
Posted
over 7 years
ago
Even during the summer break the Ditto team worked hard in order to provide the next milestone release. Here it is:
Milestone 0.8.0-M1.
Have a look at the Milestone 0.8.0-M1 release notes for what changed in detail and why
there was a version bump
... [More]
from 0.3.0-M2 to 0.8.0-M1.
The main changes and new features are
security enhancement by making some of Ditto’s headers not settable from the outside
report application metrics to Prometheus
automatically form a cluster when running in Kubernetes
improvement of Ditto’s things-service memory consumption
stabilization of the connectivity to AMQP 1.0 and 0.9.1
Artifacts
The new Java artifacts have been published at the Eclipse Maven repository
as well as Maven central.
The Docker images have been pushed to Docker Hub:
eclipse/ditto-policies
eclipse/ditto-things
eclipse/ditto-things-search
eclipse/ditto-gateway
eclipse/ditto-connectivity
eclipse/ditto-concierge
–
The Eclipse Ditto team
[Less]
|
|
Posted
over 7 years
ago
Today we, the Eclipse Ditto team, are happy to announce our next milestone 0.3.0-M2.
The main changes are
improvement of Ditto’s cluster performance with many managed Things
a new Ditto service ditto-concierge was added for this
... [More]
improved cluster bootstrapping based on DNS with the potential to easy plugin other mechanism (e.g. for Kubernetes)
Have a look at the Milestone 0.3.0-M2 release notes for a detailed description of what
changed.
Artifacts
The new Java artifacts have been published at the Eclipse Maven repository
as well as Maven central.
The Docker images have been pushed to Docker Hub:
eclipse/ditto-policies
eclipse/ditto-things
eclipse/ditto-things-search
eclipse/ditto-gateway
eclipse/ditto-connectivity
eclipse/ditto-concierge
–
The Eclipse Ditto team
[Less]
|
|
Posted
over 7 years
ago
With the recently released Ditto milestone 0.3.0-M1 the connectivity
to AMQP 1.0 endpoints can now be established in a durable and stable way (including failovers, etc.).
That means Ditto now is ready to be connected to Eclipse Hono’s “northbound”
... [More]
API which
is provided via AMQP 1.0.
By doing so it is for example possible to receive Hono telemetry
messages (see heading “Northbound Operations”) which a device demo-device connected to the “southbound” of Hono sends
via HTTP or MQTT (the currently available protocol adapters of Hono) in Ditto.
When received, the payload can be translated into a format Ditto understands in order to update the
digital twin of the demo-device device and provide API access to the twin, e.g. via HTTP
or WebSocket.
This blog post walks through the steps required to connect Ditto and Hono by adding a connection between the Hono and
Ditto sandboxes at
hono.eclipse.org
ditto.eclipse.org
Scenario
The following graphic illustrates the scenario:
Scenario for providing a digital twin in Ditto of a device connected via Hono
Let’s assume for this tutorial that we have a device (e.g. containing a sensor) demo-device which is capable of
measuring temperature and humidity.
This device sends the sensor telemetry data every 5 minutes via MQTT into the cloud in either of the following formats:
{
"temp": 23.42,
"hum": 44.42
}
{
"temp": 23.42
}
{
"hum": 44.42
}
We want to create a digital twin for this device in order to access the device’s sensor data as API via Eclipse Ditto.
Steps in Hono
The steps in order to get started with Eclipse Hono are documented in the
Hono getting started and in a new
Blog post about using multi-tenancy in Eclipse Hono.
We show them very briefly here as well but in order to comprehend what and why we are doing what we do please consult
the Hono documentation.
Create a tenant
First of all, create a new Hono tenant (we chose the tenant name org.eclipse.ditto):
$ curl -X POST -i -H 'Content-Type: application/json' -d '{"tenant-id": "org.eclipse.ditto"}' http://hono.eclipse.org:28080/tenant
Register a device
Register a new device in Hono (we chose the device-id demo-device):
$ curl -X POST -i -H 'Content-Type: application/json' -d '{"device-id": "demo-device"}' http://hono.eclipse.org:28080/registration/org.eclipse.ditto
Add a device credential
In order for the device being able to send telemetry it needs to authenticate. For that we will need to add a credential
for that device in Hono.
We choose the hashed-password type:
$ PWD_HASH=$(echo -n 'demo-device-password' | openssl dgst -binary -sha512 | base64 -w 0)
$ curl -X POST -i -H 'Content-Type: application/json' -d '{
"device-id": "demo-device",
"type": "hashed-password",
"auth-id": "demo-device-auth",
"secrets": [{
"hash-function" : "sha-512",
"pwd-hash": "'$PWD_HASH'"
}]
}' http://hono.eclipse.org:28080/credentials/org.eclipse.ditto
Publish data
You are now able to publish telemetry (or also event) data via the Hono HTTP adapter:
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"temp": 23.07}' http://hono.eclipse.org:8080/telemetry
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"hum": 45.85}' http://hono.eclipse.org:8080/telemetry
However as there is not yet a consumer listening for the messages, the Hono HTTP adapter will for example return an
error code 503 - Service unavailable when publishing a telemetry message.
Alternatively you can also publish telemetry data via MQTT:
$ mosquitto_pub -u '[email protected]' -P demo-device-password -t telemetry -m '{"temp": 23.07}'
$ mosquitto_pub -u '[email protected]' -P demo-device-password -t telemetry -m '{"hum": 45.85}'
In the following steps we will register the missing consumer in Ditto by creating a connection to the Hono tenant
in Ditto’s connectivity.
Steps in Ditto
We want to create a digital twin of the device connected to Eclipse Hono in order to access its latest reported state
via the Ditto HTTP API, in order to be able to find it in a population of digital twins or
in order to be notified about changed via an API optimized for the web.
Create a digital twin
The first step is to create a skeleton for the digital twin by creating a Ditto Thing.
Notice that we authenticate with the sandbox user demo5 - a default Policy is implicitly
created so that only that user may read+write the created Thing.
$ curl -X PUT -i -u demo5:demo -H 'Content-Type: application/json' -d '{
"attributes": {
"location": "Germany"
},
"features": {
"temperature": {
"properties": {
"value": null
}
},
"humidity": {
"properties": {
"value": null
}
}
}
}' https://ditto.eclipse.org/api/2/things/org.eclipse.ditto:demo-device
Make sure the digital twin was created:
$ curl -i -u demo5:demo https://ditto.eclipse.org/api/2/things/org.eclipse.ditto:demo-device
Create a connection to Hono
Ditto recently added support for managing connections to foreign endpoints
(currently to AMQP 1.0 or to AMQP 0.9.1). As Hono provides an AMQP 1.0 endpoint, a connection can be added in Ditto
which connects to Hono and acts as a “northbound” consumer.
The following configuration for the connection has to be applied:
AMQP 1.0 hostname: hono.eclipse.org
AMQP 1.0 port: 15672
username: consumer@HONO
password: verysecret
sources:
telemetry/org.eclipse.ditto
event/org.eclipse.ditto
Test the connection
Send the following “test connection” command via HTTP in order to test if the Ditto sandbox can connect to the Hono one.
$ curl -X POST -i -u devops:devopsPw1! -H 'Content-Type: application/json' -d '{
"targetActorSelection": "/system/sharding/connection",
"headers": {
"aggregate": false
},
"piggybackCommand": {
"type": "connectivity.commands:testConnection",
"connection": {
"id": "hono-sandbox-connection-1",
"connectionType": "amqp-10",
"connectionStatus": "open",
"uri": "amqp://consumer%40HONO:[email protected]:15672",
"failoverEnabled": true,
"sources": [{
"addresses": [
"telemetry/org.eclipse.ditto",
"event/org.eclipse.ditto"
],
"authorizationContext": ["nginx:demo5"]
}]
}
}
}' https://ditto.eclipse.org/devops/piggyback/connectivity?timeout=8000
The result should be:
{
"?": {
"-1": {
"type": "connectivity.responses:testConnection",
"status": 200,
"connectionId": "hono-sandbox-connection-1",
"testResult": "ditto-cluster=Success(successfully connected + initialized mapper)"
}
}
}
Great, it looks like with the provided credentials we can connect to the Hono sandbox.
Define a payload mapping
In the scenario we described the payloads our device sends via MQTT. As those JSON payloads are missing
some information required for Ditto to map it to a Ditto Protocol message Ditto uses for
updating the digital twin, we have to configure a payload mapping in order to add the
missing information.
Whenever one of the 3 following messages arrives at Ditto’s consumer, a payload mapping should be performed:
{
"temp": 23.42,
"hum": 44.42
}
{
"temp": 23.42
}
{
"hum": 44.42
}
A JavaScript based mapping which exactly does this could look like this:
function mapToDittoProtocolMsg(
headers,
textPayload,
bytePayload,
contentType
) {
if (contentType !== "application/json") {
return null; // only handle messages with content-type application/json
}
var jsonData = JSON.parse(textPayload);
var temperature = jsonData.temp;
var humidity = jsonData.hum;
var path;
var value;
if (temperature != null && humidity != null) {
path = "/features";
value = {
temperature: {
properties: {
value: temperature
}
},
humidity: {
properties: {
value: humidity
}
}
};
} else if (temperature != null) {
path = "/features/temperature/properties/value";
value = temperature;
} else if (humidity != null) {
path = "/features/humidity/properties/value";
value = humidity;
}
if (!path || !value) {
return null;
}
return Ditto.buildDittoProtocolMsg(
"org.eclipse.ditto", // the namespace we use
headers["device_id"], // Hono sets the authenticated device-id in this header
"things", // it is a Thing entity we want to update
"twin", // we want to update the twin
"commands",
"modify", // command = modify
path,
headers, // copy all headers as Ditto headers
value
);
}
In order to add this script to the connection we want to create, the newlines have to be replaced by \n so that
the script fits in a single line JSON string and the " characters have to be replaced with \":
"function mapToDittoProtocolMsg(\n headers,\n textPayload,\n bytePayload,\n contentType\n) {\n\n if (contentType !== \"application/json\") {\n return null;\n }\n\n var jsonData = JSON.parse(textPayload);\n var temperature = jsonData.temp;\n var humidity = jsonData.hum;\n \n var path;\n var value;\n if (temperature != null && humidity != null) {\n path = \"/features\";\n value = {\n temperature: {\n properties: {\n value: temperature\n }\n },\n humidity: {\n properties: {\n value: humidity\n }\n }\n };\n } else if (temperature != null) {\n path = \"/features/temperature/properties/value\";\n value = temperature;\n } else if (humidity != null) {\n path = \"/features/humidity/properties/value\";\n value = humidity;\n }\n \n if (!path || !value) {\n return null;\n }\n\n return Ditto.buildDittoProtocolMsg(\n \"org.eclipse.ditto\",\n headers[\"device_id\"],\n \"things\",\n \"twin\",\n \"commands\",\n \"modify\",\n path,\n headers,\n value\n );\n}"
Create the connection
We use the payload of the previous “test connection” command and add the JavaScript mapping script from above in order
to specify the “create connection” command, which we will use to create the connection between Eclipse Hono and Ditto:
$ 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": "hono-sandbox-connection-1",
"connectionType": "amqp-10",
"connectionStatus": "open",
"uri": "amqp://consumer@HONO:[email protected]:15672",
"failoverEnabled": true,
"sources": [{
"addresses": [
"telemetry/org.eclipse.ditto",
"event/org.eclipse.ditto"
],
"authorizationContext": ["nginx:demo5"],
}],
"mappingContext": {
"mappingEngine": "JavaScript",
"options": {
"incomingScript": "function mapToDittoProtocolMsg(\n headers,\n textPayload,\n bytePayload,\n contentType\n) {\n\n if (contentType !== \"application/json\") {\n return null;\n }\n\n var jsonData = JSON.parse(textPayload);\n var temperature = jsonData.temp;\n var humidity = jsonData.hum;\n \n var path;\n var value;\n if (temperature != null && humidity != null) {\n path = \"/features\";\n value = {\n temperature: {\n properties: {\n value: temperature\n }\n },\n humidity: {\n properties: {\n value: humidity\n }\n }\n };\n } else if (temperature != null) {\n path = \"/features/temperature/properties/value\";\n value = temperature;\n } else if (humidity != null) {\n path = \"/features/humidity/properties/value\";\n value = humidity;\n }\n \n if (!path || !value) {\n return null;\n }\n\n return Ditto.buildDittoProtocolMsg(\n \"org.eclipse.ditto\",\n headers[\"device_id\"],\n \"things\",\n \"twin\",\n \"commands\",\n \"modify\",\n path,\n headers,\n value\n );\n}"
}
}
}
}
}' https://ditto.eclipse.org/devops/piggyback/connectivity?timeout=8000
When establishing the connection + parsing the JavaScript worked, we get a success result as HTTP response again,
otherwise an error message would be returned.
Retrieve connection metrics
After the connection was created, we can use the following command in order to retrieve the current connection status
and some metrics about how many messages were consumed:
$ curl -X POST -i -u devops:devopsPw1! -H 'Content-Type: application/json' -d '{
"targetActorSelection": "/system/sharding/connection",
"headers": {
"aggregate": false
},
"piggybackCommand": {
"type": "connectivity.commands:retrieveConnectionMetrics",
"connectionId": "hono-sandbox-connection-1"
}
}' https://ditto.eclipse.org/devops/piggyback/connectivity?timeout=8000
The result looks like this:
{
"?": {
"-1": {
"type": "connectivity.responses:aggregatedResponse",
"status": 200,
"connectionId": "hono-sandbox-connection-1",
"responsesType": "connectivity.responses:retrieveConnectionMetrics",
"responses": {
"1": {
"type": "connectivity.responses:retrieveConnectionMetrics",
"status": 200,
"connectionId": "hono-sandbox-connection-1",
"connectionMetrics": {
"connectionStatus": "open",
"connectionStatusDetails": "Connected at 2018-04-30T12:43:13.050Z",
"inConnectionStatusSince": "2018-04-30T12:43:13.050Z",
"clientState": "CONNECTED",
"sourcesMetrics": [
{
"addressMetrics": {
"event/org.eclipse.ditto-0": {
"status": "open",
"statusDetails": "Started at 2018-04-30T12:43:13.038Z",
"messageCount": 0
},
"telemetry/org.eclipse.ditto-0": {
"status": "open",
"statusDetails": "Started at 2018-04-30T12:43:13.039Z",
"messageCount": 2,
"lastMessageAt": "2018-04-30T12:51:12.537Z"
}
},
"consumedMessages": 2
}
],
"targetsMetrics": []
}
}
}
}
}
}
Test the integration
Whenever the device now sends telemetry in its own JSON format
the message count of the connection metrics in Ditto should be increased by one
the digital twin with the Thing ID org.eclipse.ditto:demo-device should receive the updated value which is also
reflected at the twin’s HTTP endpoint
https://ditto.eclipse.org/api/2/things/org.eclipse.ditto:demo-device
Verify that by simulate sending telemetry using the Hono HTTP adapter:
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"temp": 14.51}' http://hono.eclipse.org:8080/telemetry
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"hum": 52.17}' http://hono.eclipse.org:8080/telemetry
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"temp": 23.07, "hum": 45.85}' http://hono.eclipse.org:8080/telemetry
Try it out for yourself and give us (the Ditto and the Hono teams) feedback what you like or what could be improved.
–
The Eclipse Ditto team
[Less]
|
|
Posted
over 7 years
ago
With the recently released Ditto milestone 0.3.0-M1 the connectivity
to AMQP 1.0 endpoints can now be established in a durable and stable way (including failovers, etc.).
That means Ditto now is ready to be connected to Eclipse Hono’s “northbound”
... [More]
API which
is provided via AMQP 1.0.
By doing so it is for example possible to receive Hono telemetry
messages (see heading “Northbound Operations”) which a device demo-device connected to the “southbound” of Hono sends
via HTTP or MQTT (the currently available protocol adapters of Hono) in Ditto.
When received, the payload can be translated into a format Ditto understands in order to update the
digital twin of the demo-device device and provide API access to the twin, e.g. via HTTP
or WebSocket.
This blog post walks through the steps required to connect Ditto and Hono by adding a connection between the Hono and
Ditto sandboxes at
hono.eclipse.org
ditto.eclipse.org
Scenario
The following graphic illustrates the scenario:
Scenario for providing a digital twin in Ditto of a device connected via Hono
Let’s assume for this tutorial that we have a device (e.g. containing a sensor) demo-device which is capable of
measuring temperature and humidity.
This device sends the sensor telemetry data every 5 minutes via MQTT into the cloud in either of the following formats:
{
"temp": 23.42,
"hum": 44.42
}
{
"temp": 23.42
}
{
"hum": 44.42
}
We want to create a digital twin for this device in order to access the device’s sensor data as API via Eclipse Ditto.
Steps in Hono
The steps in order to get started with Eclipse Hono are documented in the
Hono getting started and in a new
Blog post about using multi-tenancy in Eclipse Hono.
We show them very briefly here as well but in order to comprehend what and why we are doing what we do please consult
the Hono documentation.
Create a tenant
First of all, create a new Hono tenant (we chose the tenant name org.eclipse.ditto):
$ curl -X POST -i -H 'Content-Type: application/json' -d '{"tenant-id": "org.eclipse.ditto"}' http://hono.eclipse.org:28080/tenant
Register a device
Register a new device in Hono (we chose the device-id demo-device):
$ curl -X POST -i -H 'Content-Type: application/json' -d '{"device-id": "demo-device"}' http://hono.eclipse.org:28080/registration/org.eclipse.ditto
Add a device credential
In order for the device being able to send telemetry it needs to authenticate. For that we will need to add a credential
for that device in Hono.
We choose the hashed-password type:
$ PWD_HASH=$(echo -n 'demo-device-password' | openssl dgst -binary -sha512 | base64 -w 0)
$ curl -X POST -i -H 'Content-Type: application/json' -d '{
"device-id": "demo-device",
"type": "hashed-password",
"auth-id": "demo-device-auth",
"secrets": [{
"hash-function" : "sha-512",
"pwd-hash": "'$PWD_HASH'"
}]
}' http://hono.eclipse.org:28080/credentials/org.eclipse.ditto
Publish data
You are now able to publish telemetry (or also event) data via the Hono HTTP adapter:
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"temp": 23.07}' http://hono.eclipse.org:8080/telemetry
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"hum": 45.85}' http://hono.eclipse.org:8080/telemetry
However as there is not yet a consumer listening for the messages, the Hono HTTP adapter will for example return an
error code 503 - Service unavailable when publishing a telemetry message.
Alternatively you can also publish telemetry data via MQTT:
$ mosquitto_pub -u '[email protected]' -P demo-device-password -t telemetry -m '{"temp": 23.07}'
$ mosquitto_pub -u '[email protected]' -P demo-device-password -t telemetry -m '{"hum": 45.85}'
In the following steps we will register the missing consumer in Ditto by creating a connection to the Hono tenant
in Ditto’s connectivity.
Steps in Ditto
We want to create a digital twin of the device connected to Eclipse Hono in order to access its latest reported state
via the Ditto HTTP API, in order to be able to find it in a population of digital twins or
in order to be notified about changed via an API optimized for the web.
Create a digital twin
The first step is to create a skeleton for the digital twin by creating a Ditto Thing.
Notice that we authenticate with the sandbox user demo5 - a default Policy is implicitly
created so that only that user may read+write the created Thing.
$ curl -X PUT -i -u demo5:demo -H 'Content-Type: application/json' -d '{
"attributes": {
"location": "Germany"
},
"features": {
"temperature": {
"properties": {
"value": null
}
},
"humidity": {
"properties": {
"value": null
}
}
}
}' https://ditto.eclipse.org/api/2/things/org.eclipse.ditto:demo-device
Make sure the digital twin was created:
$ curl -i -u demo5:demo https://ditto.eclipse.org/api/2/things/org.eclipse.ditto:demo-device
Create a connection to Hono
Ditto recently added support for managing connections to foreign endpoints
(currently to AMQP 1.0 or to AMQP 0.9.1). As Hono provides an AMQP 1.0 endpoint, a connection can be added in Ditto
which connects to Hono and acts as a “northbound” consumer.
The following configuration for the connection has to be applied:
AMQP 1.0 hostname: hono.eclipse.org
AMQP 1.0 port: 15672
username: consumer@HONO
password: verysecret
sources:
telemetry/org.eclipse.ditto
event/org.eclipse.ditto
Test the connection
Send the following “test connection” command via HTTP in order to test if the Ditto sandbox can connect to the Hono one.
$ curl -X POST -i -u devops:devopsPw1! -H 'Content-Type: application/json' -d '{
"targetActorSelection": "/system/sharding/connection",
"headers": {
"aggregate": false
},
"piggybackCommand": {
"type": "connectivity.commands:testConnection",
"connection": {
"id": "hono-sandbox-connection-1",
"connectionType": "amqp-10",
"connectionStatus": "open",
"uri": "amqp://consumer%40HONO:[email protected]:15672",
"failoverEnabled": true,
"sources": [{
"addresses": [
"telemetry/org.eclipse.ditto",
"event/org.eclipse.ditto"
],
"authorizationContext": ["nginx:demo5"]
}]
}
}
}' https://ditto.eclipse.org/devops/piggyback/connectivity?timeout=8000
The result should be:
{
"?": {
"-1": {
"type": "connectivity.responses:testConnection",
"status": 200,
"connectionId": "hono-sandbox-connection-1",
"testResult": "ditto-cluster=Success(successfully connected + initialized mapper)"
}
}
}
Great, it looks like with the provided credentials we can connect to the Hono sandbox.
Define a payload mapping
In the scenario we described the payloads our device sends via MQTT. As those JSON payloads are missing
some information required for Ditto to map it to a Ditto Protocol message Ditto uses for
updating the digital twin, we have to configure a payload mapping in order to add the
missing information.
Whenever one of the 3 following messages arrives at Ditto’s consumer, a payload mapping should be performed:
{
"temp": 23.42,
"hum": 44.42
}
{
"temp": 23.42
}
{
"hum": 44.42
}
A JavaScript based mapping which exactly does this could look like this:
function mapToDittoProtocolMsg(
headers,
textPayload,
bytePayload,
contentType
) {
if (contentType !== "application/json") {
return null; // only handle messages with content-type application/json
}
var jsonData = JSON.parse(textPayload);
var temperature = jsonData.temp;
var humidity = jsonData.hum;
var path;
var value;
if (temperature != null && humidity != null) {
path = "/features";
value = {
temperature: {
properties: {
value: temperature
}
},
humidity: {
properties: {
value: humidity
}
}
};
} else if (temperature != null) {
path = "/features/temperature/properties/value";
value = temperature;
} else if (humidity != null) {
path = "/features/humidity/properties/value";
value = humidity;
}
if (!path || !value) {
return null;
}
return Ditto.buildDittoProtocolMsg(
"org.eclipse.ditto", // the namespace we use
headers["device_id"], // Hono sets the authenticated device-id in this header
"things", // it is a Thing entity we want to update
"twin", // we want to update the twin
"commands",
"modify", // command = modify
path,
headers, // copy all headers as Ditto headers
value
);
}
In order to add this script to the connection we want to create, the newlines have to be replaced by \n so that
the script fits in a single line JSON string and the " characters have to be replaced with \":
"function mapToDittoProtocolMsg(\n headers,\n textPayload,\n bytePayload,\n contentType\n) {\n\n if (contentType !== \"application/json\") {\n return null;\n }\n\n var jsonData = JSON.parse(textPayload);\n var temperature = jsonData.temp;\n var humidity = jsonData.hum;\n \n var path;\n var value;\n if (temperature != null && humidity != null) {\n path = \"/features\";\n value = {\n temperature: {\n properties: {\n value: temperature\n }\n },\n humidity: {\n properties: {\n value: humidity\n }\n }\n };\n } else if (temperature != null) {\n path = \"/features/temperature/properties/value\";\n value = temperature;\n } else if (humidity != null) {\n path = \"/features/humidity/properties/value\";\n value = humidity;\n }\n \n if (!path || !value) {\n return null;\n }\n\n return Ditto.buildDittoProtocolMsg(\n \"org.eclipse.ditto\",\n headers[\"device_id\"],\n \"things\",\n \"twin\",\n \"commands\",\n \"modify\",\n path,\n headers,\n value\n );\n}"
Create the connection
We use the payload of the previous “test connection” command and add the JavaScript mapping script from above in order
to specify the “create connection” command, which we will use to create the connection between Eclipse Hono and Ditto:
$ 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": "hono-sandbox-connection-1",
"connectionType": "amqp-10",
"connectionStatus": "open",
"uri": "amqp://consumer%40HONO:[email protected]:15672",
"failoverEnabled": true,
"sources": [{
"addresses": [
"telemetry/org.eclipse.ditto",
"event/org.eclipse.ditto"
],
"authorizationContext": ["nginx:demo5"]
}],
"mappingContext": {
"mappingEngine": "JavaScript",
"options": {
"incomingScript": "function mapToDittoProtocolMsg(\n headers,\n textPayload,\n bytePayload,\n contentType\n) {\n\n if (contentType !== \"application/json\") {\n return null;\n }\n\n var jsonData = JSON.parse(textPayload);\n var temperature = jsonData.temp;\n var humidity = jsonData.hum;\n \n var path;\n var value;\n if (temperature != null && humidity != null) {\n path = \"/features\";\n value = {\n temperature: {\n properties: {\n value: temperature\n }\n },\n humidity: {\n properties: {\n value: humidity\n }\n }\n };\n } else if (temperature != null) {\n path = \"/features/temperature/properties/value\";\n value = temperature;\n } else if (humidity != null) {\n path = \"/features/humidity/properties/value\";\n value = humidity;\n }\n \n if (!path || !value) {\n return null;\n }\n\n return Ditto.buildDittoProtocolMsg(\n \"org.eclipse.ditto\",\n headers[\"device_id\"],\n \"things\",\n \"twin\",\n \"commands\",\n \"modify\",\n path,\n headers,\n value\n );\n}"
}
}
}
}
}' https://ditto.eclipse.org/devops/piggyback/connectivity?timeout=8000
When establishing the connection + parsing the JavaScript worked, we get a success result as HTTP response again,
otherwise an error message would be returned.
Retrieve connection metrics
After the connection was created, we can use the following command in order to retrieve the current connection status
and some metrics about how many messages were consumed:
$ curl -X POST -i -u devops:devopsPw1! -H 'Content-Type: application/json' -d '{
"targetActorSelection": "/system/sharding/connection",
"headers": {
"aggregate": false
},
"piggybackCommand": {
"type": "connectivity.commands:retrieveConnectionMetrics",
"connectionId": "hono-sandbox-connection-1"
}
}' https://ditto.eclipse.org/devops/piggyback/connectivity?timeout=8000
The result looks like this:
{
"?": {
"?": {
"type": "connectivity.responses:retrieveConnectionMetrics",
"status": 200,
"connectionId": "hono-sandbox-connection-1",
"containsFailures": false,
"connectionMetrics": {
"inbound": {
"consumed": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.416Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"mapped": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.422Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"dropped": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"enforced": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.422Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
}
},
"outbound": {
"dispatched": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.439Z"
}
},
"filtered": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"mapped": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.443Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"dropped": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"published": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
}
}
},
"sourceMetrics": {
"addressMetrics": {
"event/org.eclipse.ditto": {
"consumed": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"mapped": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"dropped": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"enforced": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
}
},
"telemetry/org.eclipse.ditto": {
"consumed": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.416Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"mapped": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.422Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"dropped": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"enforced": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.422Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
}
}
}
},
"targetMetrics": {
"addressMetrics": {
"_responses": {
"dispatched": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.439Z"
}
},
"filtered": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"mapped": {
"success": {
"PT1M": 2,
"PT1H": 2,
"PT24H": 2,
"lastMessageAt": "2019-02-06T09:37:28.443Z"
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"dropped": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
},
"published": {
"success": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
},
"failure": {
"PT1M": 0,
"PT1H": 0,
"PT24H": 0,
"lastMessageAt": null
}
}
}
}
}
}
}
}
Test the integration
Whenever the device now sends telemetry in its own JSON format
the message count of the connection metrics in Ditto should be increased by one
the digital twin with the Thing ID org.eclipse.ditto:demo-device should receive the updated value which is also
reflected at the twin’s HTTP endpoint
https://ditto.eclipse.org/api/2/things/org.eclipse.ditto:demo-device
Verify that by simulate sending telemetry using the Hono HTTP adapter:
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"temp": 14.51}' http://hono.eclipse.org:8080/telemetry
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"hum": 52.17}' http://hono.eclipse.org:8080/telemetry
$ curl -X POST -i -u [email protected]:demo-device-password -H 'Content-Type: application/json' -d '{"temp": 23.07, "hum": 45.85}' http://hono.eclipse.org:8080/telemetry
Try it out for yourself and give us (the Ditto and the Hono teams) feedback what you like or what could be improved.
–
The Eclipse Ditto team
[Less]
|