Overview
Cumulocity provides a REST API that expects data in a specific format, our so-called Domain Model:
As usual, not all devices support this domain model out of the box, so some mapping is needed to map the device data to that domain model and vice-versa.
For that purpose, we originally implemented the Dynamic Mapper, an open-source project that allows such mappings in a zero-code approach. It was mainly developed for messaging protocols like MQTT and Kafka, which follow a typical pub-sub pattern.
With the latest release, we introduce a new feature that opens the dynamic mapper to also allow mapping for any HTTP inbound messages by providing a generic HTTP-Endpoint.
In the other direction we introduce a new feature to send any kind of Cumulocity data to a custom WebHook of your choice using a near real-time push-mechanism.
Let me explain how this works in detail!
Generic HTTP Endpoint
What it is about?
Imagine you have a system or a device that contains data you might want to have in Cumulocity, and your system or device is able to forward the data to any custom REST endpoint e.g. using Web Hooks or similar approach.
What is needed from Cumulocity is to provide REST endpoints to receive the data and, of course, logic implemented to map it to the Cumulocity domain model. Since now, this was only possible by implementing and hosting your own custom microservice.
With the Generic HTTP endpoint of the dynamic mapper, you don’t need to write any single line of code anymore, and you can straightaway process incoming data via HTTP in just a few minutes.
How it works
With every instance of the dynamic mapper microservice, you get a generic HTTP Endpoint connector out-of-the-box.
The idea behind the generic HTTP endpoint is that it listens on the subpath /httpConnector/**
of the dynamic mapper REST API, e.g.,
https://<CumulocityTenantURL>/service/dynamic-mapping-service/httpConnector
This endpoint is generic and accepts any POST or PUT messages of any media type.
Also, the path beyond httpConnector
can be freely used, e.g., .../httpConnector/device
. It can have multiple sub-paths, including dynamic identifiers, which might be important for you to have in Cumulocity, e.g., .../httpConnector/device/dev4711/temp
.
If you are familiar with the dynamic mapper, you might know that we implemented a concept of so-called Mappings which can be defined to map any data. For the HTTP Endpoint, we leverage the same way we did for message brokers like MQTT, but now we don’t have any topics but just sub-paths.
In the above example, we take device/dev4711/temp
as the topic we create the mapping for. Everything else is the same logic like we use for message broker messages.
Also, we support message snooping. So you can create a dummy mapping, enable snooping, and just see what is received to explore the incoming data and paths. You can use the received messages as a template to configure your mappings later on.
End-to-End example
Let’s assume we have a device that sends telemetry data to the following endpoint:
POST .../httpConnector/device/dev4711/temp
.
As we already have the default HTTP connector we can start right-away with the mapping:
1. Create Inbound Mapping
First we select JSON as mapping type
Next we select the Default Http Connector
Now we use the following mapping topic:
/device/+/temp
we change the topic sample to a valid sample e.g. /device/dev4711/temp
.
As API we select Measurement.
We toggle Create device so a new device is created if it doesn’t exists.
Finally we toggle Use external Id to make sure we use external identifiers to identify the device.
Next we do the mapping:
- Topic_Level_2 → IDENTITY.externalID
- Temperature.value → c8y_TemperatureMeasurement.T.value
- Temperature.value → c8y_TemperatureMeasurement.T.unit
- $now() → time
We test and save the mapping.
2. Activate
We can now activate our mapping by toggle the Activate button. After a short while the mapping will be acrtive the in the For Connectors colum you will see the Default Http Connector.
3. Test Mapping
We can test the mapping by using any REST client of our choice, be it Postman, curl or anythin else.
In my example I use Postman send the following request:
POST https://switschel.eu-latest.cumulocity.com/service/dynamic-mapping-service/httpConnector/device/dev4711/temp
Payload:
{
"Temperature": {
"value": 25,
"unit": "C"
},
"time": "2025-02-17T17:08:49.389+02:00"
}
Please note: The HTTP Connector endpoint must be authenticated with a valid Cumulocity user. In addition the provided role ROLE_MAPPING_HTTP_CONNECTOR_CREATE must be assigned to the user who is used to authenticate the request.
In the Device Management App in Cumulocity you should now find a device with the id dev4711 and a measurment like we have defined in our mapping:
This proofs that our mapping is succeeding and the data is created like expected.
Web Hooks
What it is about?
WebHooks are like the generic HTTP endpoint but just in the other direction: We allow you to send any data out of Cumulocity to any custom HTTP endpoint you define.
This can be used to synchronize any systems like HMI, a historian etc. with data which is available in Cumulocity. As we are using near-realtime push, it can be also used for use cases where time is critical, e.g., alarms.
The only requirement is that the target system defines an REST API or REST endpoints to receive that data.
How it works
For WebHooks, we decided to introduce a separate connector type called WebHook. Each connector needs to specify a base URL and optional data like Authentication headers or content-type representing a system. You can define as many web hook connectors as you wish. We assume that all messages sent are POST messages (so PUT / updating is currently not in scope).
Currently, as for all outbound messages, we only support JSON as a data format.
In the background, we use the Cumulocity Messaging Service to subscribe on messages of devices you define in the user interface of the mapper. This is done for each connector to make sure that each system, you have defined a web hook connector for, is receiving the messages separately and independently.
The mapping part covers again the sub-path where the data should be sent to, e.g., you have a web hook connector with a base URL https://mysystem
and an outbound mapping with the path /telemetry/measurements
which listens on all measurements with the fragment c8y_TemperatureMeasurement
. As a result, your mapped payload will be sent to
POST https://mysystem/telemetry/measurements
Same as for the HTTP endpoint, you can have identifiers as part of the path, e.g., the device identifier that should be mapped as part of the topic /device/+/telemetry/measurement
results to
POST https://mysystem/device/dev4711/telemetry/measurements
Also here, message snooping is supported. So if you don’t know what kind of data Cumulocity has available, you can use it to explore the data first and use it as templates later on.
End-to-End example
Let’s assume we have system provides the following endpoint:
/device/dev4711/telemetry/measurement
To simulate that I created an endpoint at https://endpoints.dev:
https://8f5af0dc43.endpoints.dev
To use WebHooks we need to do the following steps using the dynamic mapper:
1. Create a new WebHook Connector
In the dynamic mapper UI we go to Connectors and createa a new one. We select the “type” Webhook
.
We should give the connector a meaningful name and most important the Base Url, which is on my case the endpoints.dev instance.
Optionally we can provide an Basel Url Health Endpoint which is used to test if the system is available or not and additional headers which are required by the system e.g. Authentication or Accept Header.
2. Activate Connector
Next step is to activate the connector. With that the mapper will check if the system is available (if a health endpoint is provided) and set the status accordingly.
3. Create Outbound Mapping
Now we come to the default part which is no difference to any other outbound mapping. We create a new outbound mapping and make sure that we select our recently created connector.
As a next step we define the publish topic /device/+/telemetry/measurement
with a sample of /device/dev4711/telemetry/measurement
As filter mapping fragment we use c8y_TemperatureMeasurement
which will make sure that only measurements with that fragment will be forwarded to our web hook.
Also we wanted to use an external identifier therefor we toggle Use external id
Finally we define the following substitutions.
- IDENTITY.externalId —> TOPIC_LEVEL[2]
- c8y_TemperatureMeasurement.T.value —> Temperature.value
- c8y_TemperatureMeasurement.T.unit —> Temperature.unit
- time —> time
4. Activate Mapping
Toggle the Activate button so the mapping gets activated
5. Create a Subscription
With our connector and mapping up and ready we now need to define for which devices we want to forward message to our webhook. Therefor we need to create Subscription by clicking on Manage subscriptions.
We can either select a group of devices or single devices. In my example I use the device which has been created by the HTTP Inbound connector and search for dev4711
.
When clicking on Save you should see that device in the list of active subscriptions.
6. Testing
Now it’s time to test our chain. We start by creating a new measurement using the Cumulocity REST API for the device we just subscribed on
Please note: We have to use the internal ID which is printed as System ID in our subscription list as source.id as part of the payload.
POST https://switschel.eu-latest.cumulocity.com/measurement/measurements
Payload:
{
"time": "2025-02-18T13:25:00.000Z",
"source": {
"id": "14121580655" //Device dev4711
},
"type": "c8y_Temperature",
"c8y_TemperatureMeasurement": {
"T": {
"value": -10,
"unit": "°C"
}
}
}
Check endpoints.dev if the request has been received and is as expected:
As you can see everything works smoothly and the target system received the message sent by our webhook.
Try it out yourself!
Hope I was able to make you curious?! You can try it out yourself by installing the latest version 4.8.0+ of the Dynamic Mapper.
Check out the installation guide if you need further assistance on installing it into your tenant.
As always we are happy to get your feedback about it either here in the comments or as an issue at GitHub.
If you are interested in contributing your idea or feature please also just approach us!
Developer & Maintainer: @Christof_Strack @Stefan_Witschel
Special Community Award Challenge
To get additional 200 points for the community awards and make your way up to the top 5 community member who get a nice goodie package, be the first one who comment a screen of your custom HTTP Inbound or Webhook mapping