View a markdown version of this page

Substitution templates - Amazon IoT Core
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Substitution templates

You can use a substitution template to augment the JSON data returned when a rule is triggered and Amazon IoT performs an action. The syntax for a substitution template is ${expression}, where expression can be any expression supported by Amazon IoT in SELECT clauses, WHERE clauses, and Amazon IoT rule actions. This expression can be plugged into an action field on a rule, allowing you to dynamically configure an action. In effect, this feature substitutes a piece of information in an action. This includes functions, operators, and information present in the original message payload.

Important

Because an expression in a substitution template is evaluated separately from the "SELECT ..." statement, you can't reference an alias created using the AS clause. You can only reference information present in the original payload, functions, and operators.

For more information about supported expressions, see Amazon IoT SQL reference.

The following rule actions support substitution templates. Each action supports different fields that can be substituted.

Substitution templates appear in the action parameters within a rule:

{ "sql": "SELECT *, timestamp() AS timestamp FROM 'my/iot/topic'", "ruleDisabled": false, "actions": [{ "republish": { "topic": "${topic()}/republish", "roleArn": "arn:aws:iam::123456789012:role/my-iot-role" } }] }

If this rule is triggered by the following JSON published to my/iot/topic:

{ "deviceid": "iot123", "temp": 54.98, "humidity": 32.43, "coords": { "latitude": 47.615694, "longitude": -122.3359976 } }

Then this rule publishes the following JSON to my/iot/topic/republish, which Amazon IoT substitutes from ${topic()}/republish:

{ "deviceid": "iot123", "temp": 54.98, "humidity": 32.43, "coords": { "latitude": 47.615694, "longitude": -122.3359976 }, "timestamp": 1579637878451 }

Per-element substitution for array payloads in Amazon IoT rules

With Amazon IoT, you can use the standard substitution template ${expression}. This template resolves one time per message, against the message payload as the device published it, before the rule's SQL statement transforms it. If your message payload is a JSON array, use the per-element sequence @{field} instead. This sequence resolves one time for each element of the payload that the rule's SQL statement produces. The rule action writes one InfluxDB line-protocol point per element. It uses the value from the matching element.

Note

The two sequences read different payloads, so they can resolve to different values for the same field name. If the rule's SQL statement renames or reshapes fields, inside @{field} you must reference the field name as it appears in the SQL output. If an element doesn't contain the field, the sequence resolves to an empty value. It doesn't fall back to a message-level value, and Amazon IoT drops an empty tag value from the line protocol that it writes.

Important

The @{field} sequence works only in the Amazon IoT InfluxDB rule action configuration. It doesn't work in these places:

  • The rule SQL statement (the SELECT, WHERE, or SET clauses)

  • Any other rule action

  • A function. The sequence can't contain one, such as @{upper(room)}. You also can't pass the sequence to a substitution template function, because a single configuration value can't contain both @{...} and ${...}.

  • The rule's error action, even when that error action is an InfluxDB action. The error action runs one time for the message, so it never resolves per element.

If you use it in any of these places, the CreateTopicRule and ReplaceTopicRule operations fail with an error.

The per-element sequence @{field} has the following requirements:

  • Must reference a single field, such as @{room} or @{meta.sensor_id}

  • Must not include functions, arithmetic, comparisons, or literals

  • Must appear at most one time in a configuration value

  • Must not appear in the same configuration value as a ${...} substitution template

  • Must appear in a configuration value, not a key (for example, an InfluxDB tag value but not a tag key)

Map array elements to InfluxDB points

In this example, an InfluxDB rule action sets the measurement name (tableName) to @{measurement_type} and a location tag to @{room}:

{ "topicRulePayload": { "sql": "SELECT * FROM 'iot/topic'", "ruleDisabled": false, "awsIotSqlVersion": "2016-03-23", "actions": [ { "influxDB": { "destinationArn": "arn:aws:iot:us-east-1:123456789012:ruledestination/influxdb/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111", "roleArn": "arn:aws:iam::123456789012:role/aws_iot_influxdb", "databaseName": "device_metrics", "tableName": "@{measurement_type}", "organization": "my_organization", "tags": { "location": "@{room}" }, "timestampUnit": "ms" } } ] } }

The following array payload triggers the rule:

[ { "measurement_type": "temperature", "room": "kitchen", "value": 5, "timestamp": 1700000000000 }, { "measurement_type": "humidity", "room": "bedroom", "value": 15, "timestamp": 1700000001000 } ]

The action writes one InfluxDB line-protocol point for each element of the array. Each element resolves @{measurement_type} to its own measurement name and @{room} to its own location tag:

temperature,location=kitchen value=5i 1700000000000 humidity,location=bedroom value=15i 1700000001000
Note

Amazon IoT excludes any field that a @{field} sequence references from the field set. Amazon IoT uses that field's value as the measurement name or tag value. In this example, measurement_type supplies the measurement and room supplies the location tag. Amazon IoT excludes both, so each point keeps only value as a field.

The preceding example uses SELECT *, so the payload that the action receives matches the payload that the device published. If the SQL statement renames a field, use the name that appears in the SQL output. For example, if the statement includes room AS location_name, use @{location_name} instead of @{room}.

Resolve against a payload that the SQL statement produces

The payload that the action receives isn't always the payload that the device published. In this example, the device publishes an object that contains an array of readings:

{ "device_id": "sensor-1", "readings": [ { "measurement_type": "temperature", "room": "kitchen", "value": 5, "timestamp": 1700000000000 }, { "measurement_type": "humidity", "room": "bedroom", "value": 15, "timestamp": 1700000001000 } ] }

The rule uses SELECT VALUE to return the readings array as the top-level payload. For more information, see Output an Array as a top-level object.

SELECT VALUE readings FROM 'iot/topic'

The action receives the following array, even though the device published an object. It writes the same two points as the preceding example, because each element still contains measurement_type, room, and value.

[ { "measurement_type": "temperature", "room": "kitchen", "value": 5, "timestamp": 1700000000000 }, { "measurement_type": "humidity", "room": "bedroom", "value": 15, "timestamp": 1700000001000 } ]
Note

The device_id field is in the payload that the device published, but not in the array that the SQL statement produces. For that reason, @{device_id} doesn't resolve in this rule. Reference only fields that appear in the elements of the produced array.