Cybus::Mapping

The mapping resource describes how data is mapped from one MQTT topic or an array of topics (subscribe) to another MQTT topic (publish) with the possibility of adding rules to perform powerful transformations of the data right inside the Connectware.

Mappings by default happen between topics of the internal broker but are not limited to. Mappings may be established between different MQTT brokers.

Properties

Property

Type

Required

Default

mappings

object[]

Required

targetState

enum

Optional

"enabled"

agentName

string

Optional

"protocol-mapper"

inputBuffering

object

Optional

mappings

  • is required

  • type: object[]

  • All items must be of the type: object with following properties:

Property

Type

Required

subscribe

object

Required

publish

object

Required

rules

array

Optional

subscribe

The subscribe part of the Mapping can subscribe either to one single endpoint/topic, or to an array of endpoints or topics. When subscribing to an array of endpoints/topics, the collect rule is particularly useful in the rules property of this mapping entry.

  • type: object or object[]

Property

Type

Required

endpoint

string

One of endpoint or topic

topic

string

One of endpoint or topic

qos

integer

Optional

connection

string

Optional

label

string

Optional

endpoint

Reference to an Cybus::Endpoint resource

  • type: string

topic

An explicit topic name. NOTE: This topic will not automatically be prefixed!

  • type: string

qos

The quality of service for mqtt messages.

  • type: integer

  • allowed values: 0, 1, 2

  • default: 0

connection

Reference to an Cybus::Connection resource

  • type: string

label

An optional label used as the key of the output object built when the collect rule is used in combination with an array of subscriptions. If no label is provided, the topic is used instead.

Labels can be dynamically constructed when Wildcards are used in the topics. To construct dynamic labels the name of a wildcard enclosed in curly braces has to be used to specify that the final value of the label will be replaced with the value of the wildcard.

When using dynamic labels the label most be enclosed in double quotes.

Example:

 1testMapping:
 2  type: Cybus::Mapping
 3  properties:
 4    mappings:
 5      - subscribe:
 6          - topic: factory/+machineName/+sensorName
 7            label: "Machine: {machineName} Sensor: {sensorName}"
 8        publish:
 9          topic: 'factory/out'
10        rules:
11          - collect: {}

In this case a message arriving at /factory/Robot001/Temperature will yield a label Machine: Robot001 Sensor: Temperature and a message arriving at /factory/Robot001/Current will yield a label of Machine: Robot001 Sensor: Current

The wildcards used in the topic can be placed in any order in the label template as the matching to wildcards is done by name so another option for the previous example could be a label configured as “Sensor: {sensorName} Machine: {machineName}” which will yield a label “Sensor: Temperature Machine: Robot001”

Dynamic labels make it easy to write Mappings that use the collect rule in a very brief manner.

  • type: string

publish

  • type: object

Property

Type

Required

endpoint

string

One of endpoint or topic

topic

string

One of endpoint or topic

qos

integer

Optional

retain

boolean

Optional

connection

string

Optional

endpoint

Reference to an Cybus::Endpoint resource

  • type: string

topic

An explicit topic name. NOTE: This topic will not automatically be prefixed!

  • type: string

qos

The quality of service for mqtt messages.

  • type: integer

  • allowed values: 0, 1, 2

  • default: 0

Note: This particular qos setting is applied for only for this particular subscribe (or publish) MQTT connection of this particular mapping, i.e. from the broker to the protocol-mapper instance of this mapping or the other way round. If your intention is to set up an end-to-end data connection with qos level 1 or 2, every single MQTT connection involved must have this specific qos level set!

retain

Whether the last message should be retained (last-value-cached) on the internal or external broker (default: false).

  • type: boolean

  • default: false

connection

Reference to an Cybus::Connection resource

  • type: string

rules

This modifies your payload/topic while before publishing it.

targetState

  • is optional

  • type: enum

  • default: "enabled"

  • The value of this property must be equal to one of the below

    • enabled

    • disabled

agentName

  • is optional

  • type: string

  • default: "protocol-mapper"

If this property is set to any (non-default) value, it is used as the Agent name on which this particular Mapping resource should run. This is useful for load sharing if Mapping instances with a lot of processing rules need to be distributed on a larger number of Agent instances. However, the specified agent name must match exactly the actual agent name, otherwise an error is thrown upon enabling of this resource.

Also keep in mind that each Mapping resource subscribes to the central MQTT broker for the subscribe side, and publishes the results to the central MQTT broker with the results, so running this on a distributed agent causes an extra two MQTT message transmissions for each mapping.

inputBuffering

Each mapping’s subscription receives input data. This input data at the subscription can optionally be managed through an individual input buffer (also called input queue) to establish fine-grained control for high data rate behaviour. By default, this input buffering is disabled and instead all input data is handled on the global event queue, which works fine as long as there is no risk of out-of-memory exceptions due to unexpected slow data processing or forwarding.

When enabling the individual input buffer, the buffer properties determine the behaviour in situations when the input buffer is filling up. The buffer is filling up when the message arrival rate is larger than the processing data rate or the forwarding (publishing) data rate. Or, in other words, the input buffer is filling up if the messages arrive faster than how they can be processed or be forwarded (published). If this situation happens for longer time durations, the input buffer will reach its configured capacity limits and arriving messages will be dropped, so that the system will not run into an uncontrollable out-of-memory exception. This is a fundamental and unavoidable property of distributed systems due to its finite resources. But the actual behaviour of the input buffer can be adapted to the actual application scenario by setting the properties in the inputBuffering section (optional).

Supported properties are (all optional):

  • enabled (type: boolean, default: false) Enable or disable input buffering.

  • maxInputBufferSize (type: integer, default: 5000) Maximum number of input messages that are queued in the input buffer. Exceeding messages will be discarded. Adjust this to a higher value if you are handling bursty traffic.

  • maxConcurrentMessages (type: integer, default: 2) Maximum number of concurrently processed messages as long as the input buffer queue is non-empty.

  • waitingTimeOnEmptyQueue (type: integer, default: 10) Waiting time in milliseconds after the input buffer queue ran empty and before checking again for newly queued input messages. Regardless of this value, on non-empty input buffer queue all messages will be processed without waiting time in between until the queue is empty again.

Mapping Concept

It is possible to map data from one topic to another, from endpoints to topics, from topics to endpoints or from endpoints to endpoints directly.

A sample is shown in the following code snippet, where the topic test/topic/from is mapped to the other topic test/topic/to, and data from the endpoint testEndpoint1 is mapped to the topic test/endpoint/to/topic.

 1testMapping:
 2  type: Cybus::Mapping
 3  properties:
 4    mappings:
 5      - subscribe:
 6          topic: test/topic/from
 7        publish:
 8          topic: test/topic/to
 9      - subscribe:
10          endpoint: !ref testEndpoint1
11        publish:
12          topic: 'test/endpoint/to/topic'

It is also possible to map data from several topics and endpoints to a single topic.

When an array of subscribe objects is provided in a mapping the data received in the subscribed topics is published to the target publish topic.

 1testMapping:
 2  type: Cybus::Mapping
 3  properties:
 4    mappings:
 5      - subscribe:
 6          - topic: test/topic/from
 7            label: test_topic_subs
 8          - endpoint: !ref testEndpoint1
 9            label: test_endpoint_1
10          - endpoint: no/labels/are/ok/too
11        publish:
12          topic: 'test/endpoint/to/topic'
13      - subscribe:
14          endpoint: regular/subscribe
15        publish:
16          topic: output/topic

Additionally if the collect rule is used all the values from the subscribed topics and endpoints are stored in a Last Value Cache and published to the target topic as an object using the labels, or the topics if no labels were provided, as keys for the object.

 1testMapping:
 2  type: Cybus::Mapping
 3  properties:
 4    mappings:
 5      - subscribe:
 6          - topic: test/topic/from
 7            label: test_topic_subs
 8          - endpoint: !ref testEndpoint1
 9            label: test_endpoint_1
10          - endpoint: no/labels/are/ok/too
11        publish:
12          topic: 'test/endpoint/to/topic'
13        rules:
14          - collect: {}

Wildcards

The mapping resource supports wildcards in both subscribe and publish mode. In most use-cases, it is desirable to have the ability to reference the actual topic value at the wildcard position either in the target topic or in the payload. Both is possible. To use this, use a named wildcard + and add a variable name after it. The content of the wildcard variable is then made available in the $context.vars object in the Transform, Filter and SetContextVars rules of a Rules Objects. The following code sample shows some combinations.

This example will swap the last two topic components:

1wildcardMapping:
2  type: Cybus::Mapping
3  properties:
4    mappings:
5      - subscribe:
6          topic: source/+a/+b
7        publish:
8          topic: target/$b/$a

This example will store some value from the message payload using the setContextVars rule, then use that value as the output topic. The expected input message must be a JSON object with at least the property value, e.g. {"value": "abc"}, and it might contain further values that are forwarded unchanged in this example.

 1wildcardMapping:
 2  type: Cybus::Mapping
 3  properties:
 4    mappings:
 5      - subscribe:
 6          topic: source/+x
 7        rules:
 8          - setContextVars:
 9              vars:
10                fromPayload: 'value'
11        publish:
12          topic: target/$x/$fromPayload

You may even map entire sub-topic trees using the # wildcard, like shown here:

1wildcardMapping:
2  type: Cybus::Mapping
3  properties:
4    mappings:
5    - subscribe:
6        topic: in/#topic
7      publish:
8        topic: out/$topic

See below some examples of how messages arriving on in are mapped to out:

  • in/hall2 -> out/hall2

  • in/hall2/machine1 -> out/hall2/machine1

Note

Since in MQTT the named ‘#’ wildcard includes the parent level while matching, a message published directly to in would simply be mapped to out in this case.

Examples

simple mapping from endpoint to custom topic

1myMapping:
2  type: Cybus::Mapping
3  properties:
4    mappings:
5      - subscribe:
6          endpoint: !ref myEndpoint
7        publish:
8          topic: !sub '${Cybus::MqttRoot}/topic-in-my-container'

relaying messages from internal broker to external one

1myMapping:
2  type: Cybus::Mapping
3  properties:
4    mappings:
5      - subscribe:
6          topic: 'internal-scope/#topic'
7        publish:
8          topic: external-scope/$topic
9          connection: !ref myMqttConnection