Skip to content

Commit f4f2061

Browse files
committed
feat(iot-actions): Support to send message to IoT Events
1 parent d91c904 commit f4f2061

13 files changed

+956
-1
lines changed

Diff for: packages/@aws-cdk/aws-iot-actions/README.md

+24
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Currently supported are:
3131
- Put records to Kinesis Data Firehose stream
3232
- Send messages to SQS queues
3333
- Publish messages on SNS topics
34+
- Put messages IoT Events input
3435

3536
## Republish a message to another MQTT topic
3637

@@ -278,3 +279,26 @@ const topicRule = new iot.TopicRule(this, 'TopicRule', {
278279
],
279280
});
280281
```
282+
283+
## Put messages IoT Events input
284+
285+
The code snippet below creates an AWS IoT Rule that put messages
286+
to an IoT Events input when it is triggered:
287+
288+
```ts
289+
import * as iotevents from '@aws-cdk/aws-iotevents';
290+
const input = new iotevents.Input(this, 'MyInput', {
291+
attributeJsonPaths: ['payload.temperature', 'payload.transactionId'],
292+
});
293+
const topicRule = new iot.TopicRule(this, 'TopicRule', {
294+
sql: iot.IotSql.fromStringAsVer20160323(
295+
"SELECT * FROM 'device/+/data'",
296+
),
297+
actions: [
298+
new actions.IotEventsPutMessageAction(input, {
299+
batchMode: true, // optional property, default is 'false'
300+
messageId: '${payload.transactionId}', // optional property, default is a new UUID
301+
}),
302+
],
303+
});
304+
```

Diff for: packages/@aws-cdk/aws-iot-actions/lib/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './cloudwatch-put-metric-action';
33
export * from './cloudwatch-set-alarm-state-action';
44
export * from './common-action-props';
55
export * from './firehose-put-record-action';
6+
export * from './iotevents-put-message-action';
67
export * from './iot-republish-action';
78
export * from './kinesis-put-record-action';
89
export * from './lambda-function-action';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as iam from '@aws-cdk/aws-iam';
2+
import * as iot from '@aws-cdk/aws-iot';
3+
import * as iotevents from '@aws-cdk/aws-iotevents';
4+
import { CommonActionProps } from './common-action-props';
5+
import { singletonActionRole } from './private/role';
6+
7+
/**
8+
* Configuration properties of an action for the IoT Events.
9+
*/
10+
export interface IotEventsPutMessageActionProps extends CommonActionProps {
11+
/**
12+
* Whether to process the event actions as a batch.
13+
*
14+
* When batchMode is true, you can't specify a messageId.
15+
*
16+
* When batchMode is true and the rule SQL statement evaluates to an Array,
17+
* each Array element is treated as a separate message when Events by calling BatchPutMessage.
18+
* The resulting array can't have more than 10 messages.
19+
*
20+
* @default false
21+
*/
22+
readonly batchMode?: boolean;
23+
24+
/**
25+
* The ID of the message.
26+
*
27+
* When batchMode is true, you can't specify a messageId--a new UUID value will be assigned.
28+
* Assign a value to this property to ensure that only one input (message) with a given messageId will be processed by an AWS IoT Events detector.
29+
*
30+
* @default - none -- a new UUID value will be assigned
31+
*/
32+
readonly messageId?: string;
33+
}
34+
35+
/**
36+
* The action to put the message from an MQTT message to the IoT Events input.
37+
*/
38+
export class IotEventsPutMessageAction implements iot.IAction {
39+
private readonly batchMode?: boolean;
40+
private readonly messageId?: string;
41+
private readonly role?: iam.IRole;
42+
43+
/**
44+
* @param input The IoT Events input to put messages.
45+
* @param props Optional properties to not use default
46+
*/
47+
constructor(private readonly input: iotevents.IInput, props: IotEventsPutMessageActionProps = {}) {
48+
this.batchMode = props.batchMode;
49+
this.messageId = props.messageId;
50+
this.role = props.role;
51+
52+
if (this.batchMode && this.messageId) {
53+
throw new Error('messageId is not allowed when batchMode is true');
54+
}
55+
}
56+
57+
bind(rule: iot.ITopicRule): iot.ActionConfig {
58+
const role = this.role ?? singletonActionRole(rule);
59+
this.input.grantWrite(role);
60+
61+
return {
62+
configuration: {
63+
iotEvents: {
64+
batchMode: this.batchMode,
65+
inputName: this.input.inputName,
66+
messageId: this.messageId,
67+
roleArn: role.roleArn,
68+
},
69+
},
70+
};
71+
}
72+
}

Diff for: packages/@aws-cdk/aws-iot-actions/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"@aws-cdk/aws-kinesisfirehose-destinations": "0.0.0",
8282
"@aws-cdk/cdk-build-tools": "0.0.0",
8383
"@aws-cdk/integ-runner": "0.0.0",
84+
"@aws-cdk/integ-tests": "0.0.0",
8485
"@aws-cdk/pkglint": "0.0.0",
8586
"@types/jest": "^27.5.2",
8687
"jest": "^27.5.1",
@@ -90,6 +91,7 @@
9091
"@aws-cdk/aws-cloudwatch": "0.0.0",
9192
"@aws-cdk/aws-iam": "0.0.0",
9293
"@aws-cdk/aws-iot": "0.0.0",
94+
"@aws-cdk/aws-iotevents": "0.0.0",
9395
"@aws-cdk/aws-kinesis": "0.0.0",
9496
"@aws-cdk/aws-kinesisfirehose": "0.0.0",
9597
"@aws-cdk/aws-lambda": "0.0.0",
@@ -106,6 +108,7 @@
106108
"@aws-cdk/aws-cloudwatch": "0.0.0",
107109
"@aws-cdk/aws-iam": "0.0.0",
108110
"@aws-cdk/aws-iot": "0.0.0",
111+
"@aws-cdk/aws-iotevents": "0.0.0",
109112
"@aws-cdk/aws-kinesis": "0.0.0",
110113
"@aws-cdk/aws-kinesisfirehose": "0.0.0",
111114
"@aws-cdk/aws-lambda": "0.0.0",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Stack verification steps:
3+
* * aws iot-data publish --topic device/mydevice/data --qos 1 --payload (echo '[{"payload":{"deviceId":"001"}},{"payload":{"deviceId":"002"}}]' | base64) --region us-east-1
4+
*/
5+
import * as iot from '@aws-cdk/aws-iot';
6+
import * as iotevents from '@aws-cdk/aws-iotevents';
7+
import * as logs from '@aws-cdk/aws-logs';
8+
import * as cdk from '@aws-cdk/core';
9+
import { IntegTest } from '@aws-cdk/integ-tests';
10+
import * as actions from '../../lib';
11+
12+
class TestStack extends cdk.Stack {
13+
public readonly detectorModelName: string;
14+
15+
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
16+
super(scope, id, props);
17+
18+
const logGroup = new logs.LogGroup(this, 'logs', { removalPolicy: cdk.RemovalPolicy.DESTROY });
19+
const topicRule = new iot.TopicRule(this, 'TopicRule', {
20+
sql: iot.IotSql.fromStringAsVer20160323(
21+
"SELECT * FROM 'device/+/data'",
22+
),
23+
errorAction: new actions.CloudWatchLogsAction(logGroup),
24+
});
25+
26+
const input = new iotevents.Input(this, 'MyInput', {
27+
attributeJsonPaths: ['payload.deviceId'],
28+
});
29+
30+
const detectorModel = new iotevents.DetectorModel(this, 'MyDetectorModel', {
31+
detectorKey: 'payload.deviceId',
32+
initialState: new iotevents.State({
33+
stateName: 'initialState',
34+
onEnter: [{
35+
eventName: 'enter',
36+
condition: iotevents.Expression.currentInput(input),
37+
}],
38+
}),
39+
});
40+
41+
topicRule.addAction(
42+
new actions.IotEventsPutMessageAction(input, {
43+
batchMode: true,
44+
}),
45+
);
46+
47+
this.detectorModelName = detectorModel.detectorModelName;
48+
}
49+
}
50+
51+
const app = new cdk.App();
52+
const stack = new TestStack(app, 'iotevents-put-message-action-test-stack');
53+
new IntegTest(app, 'iotevents', { testCases: [stack] });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":"20.0.0"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": "20.0.0",
3+
"testCases": {
4+
"iotevents/DefaultTest": {
5+
"stacks": [
6+
"iotevents-put-message-action-test-stack"
7+
],
8+
"assertionStack": "ioteventsDefaultTestDeployAssertE216288D"
9+
}
10+
}
11+
}

0 commit comments

Comments
 (0)