Skip to content

Commit 371f5ae

Browse files
authored
Merge branch 'main' into conroy/python39
2 parents eed5535 + af301dd commit 371f5ae

23 files changed

Lines changed: 932 additions & 12 deletions

packages/@aws-cdk/aws-iotevents-actions/README.md

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,78 @@ AWS IoT Events can trigger actions when it detects a specified event or transiti
2424

2525
Currently supported are:
2626

27+
- Use timer
2728
- Set variable to detector instanse
2829
- Invoke a Lambda function
2930

31+
## Use timer
32+
33+
The code snippet below creates an Action that creates the timer with duration in seconds.
34+
35+
```ts
36+
import * as iotevents from '@aws-cdk/aws-iotevents';
37+
import * as actions from '@aws-cdk/aws-iotevents-actions';
38+
39+
declare const input: iotevents.IInput;
40+
41+
const state = new iotevents.State({
42+
stateName: 'MyState',
43+
onEnter: [{
44+
eventName: 'test-event',
45+
condition: iotevents.Expression.currentInput(input),
46+
actions: [
47+
new actions.SetTimerAction('MyTimer', {
48+
duration: cdk.Duration.seconds(60),
49+
}),
50+
],
51+
}],
52+
});
53+
```
54+
55+
Setting duration by [IoT Events Expression](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-expressions.html):
56+
57+
```ts
58+
new actions.SetTimerAction('MyTimer', {
59+
durationExpression: iotevents.Expression.inputAttribute(input, 'payload.durationSeconds'),
60+
})
61+
```
62+
63+
And the timer can be reset and cleared. Below is an example of general
64+
[Device HeartBeat](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-examples-dhb.html)
65+
Detector Model:
66+
67+
```ts
68+
const online = new iotevents.State({
69+
stateName: 'Online',
70+
onEnter: [{
71+
eventName: 'enter-event',
72+
condition: iotevents.Expression.currentInput(input),
73+
actions: [
74+
new actions.SetTimerAction('MyTimer', {
75+
duration: cdk.Duration.seconds(60),
76+
}),
77+
],
78+
}],
79+
onInput: [{
80+
eventName: 'input-event',
81+
condition: iotevents.Expression.currentInput(input),
82+
actions: [
83+
new actions.ResetTimerAction('MyTimer'),
84+
],
85+
}],
86+
onExit: [{
87+
eventName: 'exit-event',
88+
actions: [
89+
new actions.ClearTimerAction('MyTimer'),
90+
],
91+
}],
92+
});
93+
const offline = new iotevents.State({ stateName: 'Offline' });
94+
95+
online.transitionTo(offline, { when: iotevents.Expression.timeout('MyTimer') });
96+
offline.transitionTo(online, { when: iotevents.Expression.currentInput(input) });
97+
```
98+
3099
## Set variable to detector instanse
31100

32101
The code snippet below creates an Action that set variable to detector instanse
@@ -44,12 +113,10 @@ const state = new iotevents.State({
44113
eventName: 'test-event',
45114
condition: iotevents.Expression.currentInput(input),
46115
actions: [
47-
actions: [
48-
new actions.SetVariableAction(
49-
'MyVariable',
50-
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
51-
),
52-
],
116+
new actions.SetVariableAction(
117+
'MyVariable',
118+
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
119+
),
53120
],
54121
}],
55122
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import * as iotevents from '@aws-cdk/aws-iotevents';
2+
import { Construct } from 'constructs';
3+
4+
/**
5+
* The action to delete an existing timer.
6+
*/
7+
export class ClearTimerAction implements iotevents.IAction {
8+
/**
9+
* @param timerName the name of the timer
10+
*/
11+
constructor(private readonly timerName: string) {}
12+
13+
bind(_scope: Construct, _options: iotevents.ActionBindOptions): iotevents.ActionConfig {
14+
return {
15+
configuration: {
16+
clearTimer: {
17+
timerName: this.timerName,
18+
},
19+
},
20+
};
21+
}
22+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1+
export * from './clear-timer-action';
12
export * from './set-variable-action';
23
export * from './lambda-invoke-action';
4+
export * from './reset-timer-action';
5+
export * from './set-timer-action';
6+
export * from './timer-duration';
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import * as iotevents from '@aws-cdk/aws-iotevents';
2+
import { Construct } from 'constructs';
3+
4+
/**
5+
* The action to reset an existing timer.
6+
*/
7+
export class ResetTimerAction implements iotevents.IAction {
8+
/**
9+
* @param timerName the name of the timer
10+
*/
11+
constructor(private readonly timerName: string) {}
12+
13+
bind(_scope: Construct, _options: iotevents.ActionBindOptions): iotevents.ActionConfig {
14+
return {
15+
configuration: {
16+
resetTimer: {
17+
timerName: this.timerName,
18+
},
19+
},
20+
};
21+
}
22+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as iotevents from '@aws-cdk/aws-iotevents';
2+
import { Construct } from 'constructs';
3+
import { TimerDuration } from './timer-duration';
4+
5+
/**
6+
* The action to create a timer with duration in seconds.
7+
*/
8+
export class SetTimerAction implements iotevents.IAction {
9+
/**
10+
* @param timerName the name of the timer
11+
* @param timerDuration the duration of the timer
12+
*/
13+
constructor(
14+
private readonly timerName: string,
15+
private readonly timerDuration: TimerDuration,
16+
) {
17+
}
18+
19+
bind(_scope: Construct, _options: iotevents.ActionBindOptions): iotevents.ActionConfig {
20+
return {
21+
configuration: {
22+
setTimer: {
23+
timerName: this.timerName,
24+
durationExpression: this.timerDuration._bind(),
25+
},
26+
},
27+
};
28+
}
29+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as iotevents from '@aws-cdk/aws-iotevents';
2+
import { Duration } from '@aws-cdk/core';
3+
4+
/**
5+
* The duration of the timer.
6+
*/
7+
export abstract class TimerDuration {
8+
/**
9+
* Create a timer-duration from Duration.
10+
*
11+
* The range of the duration is 60-31622400 seconds.
12+
* The evaluated result of the duration expression is rounded down to the nearest whole number.
13+
* For example, if you set the timer to 60.99 seconds, the evaluated result of the duration expression is 60 seconds.
14+
*/
15+
public static fromDuration(duration: Duration): TimerDuration {
16+
const seconds = duration.toSeconds();
17+
if (seconds < 60) {
18+
throw new Error(`duration cannot be less than 60 seconds, got: ${duration.toString()}`);
19+
}
20+
if (seconds > 31622400) {
21+
throw new Error(`duration cannot be greater than 31622400 seconds, got: ${duration.toString()}`);
22+
}
23+
return new TimerDurationImpl(seconds.toString());
24+
}
25+
26+
/**
27+
* Create a timer-duration from Expression.
28+
*
29+
* You can use a string expression that includes numbers, variables ($variable.<variable-name>),
30+
* and input values ($input.<input-name>.<path-to-datum>) as the duration.
31+
*
32+
* The range of the duration is 60-31622400 seconds.
33+
* The evaluated result of the duration expression is rounded down to the nearest whole number.
34+
* For example, if you set the timer to 60.99 seconds, the evaluated result of the duration expression is 60 seconds.
35+
*/
36+
public static fromExpression(expression: iotevents.Expression): TimerDuration {
37+
return new TimerDurationImpl(expression.evaluate());
38+
}
39+
40+
/**
41+
* @internal
42+
*/
43+
public abstract _bind(): string;
44+
}
45+
46+
class TimerDurationImpl extends TimerDuration {
47+
constructor(private readonly durationExpression: string) {
48+
super();
49+
}
50+
51+
public _bind() {
52+
return this.durationExpression;
53+
}
54+
}

packages/@aws-cdk/aws-iotevents-actions/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"@aws-cdk/assertions": "0.0.0",
7474
"@aws-cdk/cdk-build-tools": "0.0.0",
7575
"@aws-cdk/integ-runner": "0.0.0",
76+
"@aws-cdk/integ-tests": "0.0.0",
7677
"@aws-cdk/pkglint": "0.0.0",
7778
"@types/jest": "^27.5.2",
7879
"jest": "^27.5.1"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Template } from '@aws-cdk/assertions';
2+
import * as iotevents from '@aws-cdk/aws-iotevents';
3+
import * as cdk from '@aws-cdk/core';
4+
import * as actions from '../../lib';
5+
6+
let stack: cdk.Stack;
7+
let input: iotevents.IInput;
8+
beforeEach(() => {
9+
stack = new cdk.Stack();
10+
input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input');
11+
});
12+
13+
test('Default property', () => {
14+
// WHEN
15+
new iotevents.DetectorModel(stack, 'MyDetectorModel', {
16+
initialState: new iotevents.State({
17+
stateName: 'test-state',
18+
onEnter: [{
19+
eventName: 'test-eventName',
20+
condition: iotevents.Expression.currentInput(input),
21+
actions: [
22+
new actions.ClearTimerAction('MyTimer'),
23+
],
24+
}],
25+
}),
26+
});
27+
28+
// THEN
29+
Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', {
30+
DetectorModelDefinition: {
31+
States: [{
32+
OnEnter: {
33+
Events: [{
34+
Actions: [{
35+
ClearTimer: {
36+
TimerName: 'MyTimer',
37+
},
38+
}],
39+
}],
40+
},
41+
}],
42+
},
43+
});
44+
});
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Stack verification steps:
3+
* * put a message
4+
* * aws iotevents-data batch-put-message --region=us-east-1 --messages=messageId=(date | md5),inputName=test_input,payload=(echo '{"payload":{"deviceId":"000"}}' | base64)
5+
*/
6+
import * as iotevents from '@aws-cdk/aws-iotevents';
7+
import * as cdk from '@aws-cdk/core';
8+
import { IntegTest } from '@aws-cdk/integ-tests';
9+
import * as actions from '../../lib';
10+
11+
/**
12+
* This example will creates the detector model for Device HeartBeat Monitoring.
13+
*
14+
* @see https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-examples-dhb.html
15+
*/
16+
class TestStack extends cdk.Stack {
17+
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
18+
super(scope, id, props);
19+
20+
const input = new iotevents.Input(this, 'MyInput', {
21+
inputName: 'test_input',
22+
attributeJsonPaths: ['payload.deviceId'],
23+
});
24+
25+
const online = new iotevents.State({
26+
stateName: 'Online',
27+
onEnter: [{
28+
eventName: 'enter-event',
29+
condition: iotevents.Expression.currentInput(input),
30+
actions: [
31+
new actions.SetTimerAction('MyTimer', actions.TimerDuration.fromDuration(cdk.Duration.seconds(60))),
32+
],
33+
}],
34+
onInput: [{
35+
eventName: 'input-event',
36+
condition: iotevents.Expression.currentInput(input),
37+
actions: [
38+
new actions.ResetTimerAction('MyTimer'),
39+
],
40+
}],
41+
onExit: [{
42+
eventName: 'exit-event',
43+
actions: [
44+
new actions.ClearTimerAction('MyTimer'),
45+
],
46+
}],
47+
});
48+
const offline = new iotevents.State({ stateName: 'Offline' });
49+
50+
online.transitionTo(offline, { when: iotevents.Expression.timeout('MyTimer') });
51+
offline.transitionTo(online, { when: iotevents.Expression.currentInput(input) });
52+
53+
new iotevents.DetectorModel(this, 'MyDetectorModel', {
54+
detectorKey: 'payload.deviceId',
55+
initialState: online,
56+
});
57+
}
58+
}
59+
60+
// GIVEN
61+
const app = new cdk.App();
62+
const stack = new TestStack(app, 'iotevents-timer-actions-test-stack');
63+
new IntegTest(app, 'TimerActions', { testCases: [stack] });
64+
app.synth();
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Template } from '@aws-cdk/assertions';
2+
import * as iotevents from '@aws-cdk/aws-iotevents';
3+
import * as cdk from '@aws-cdk/core';
4+
import * as actions from '../../lib';
5+
6+
let stack: cdk.Stack;
7+
let input: iotevents.IInput;
8+
beforeEach(() => {
9+
stack = new cdk.Stack();
10+
input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input');
11+
});
12+
13+
test('Default property', () => {
14+
// WHEN
15+
new iotevents.DetectorModel(stack, 'MyDetectorModel', {
16+
initialState: new iotevents.State({
17+
stateName: 'test-state',
18+
onEnter: [{
19+
eventName: 'test-eventName',
20+
condition: iotevents.Expression.currentInput(input),
21+
actions: [
22+
new actions.ResetTimerAction('MyTimer'),
23+
],
24+
}],
25+
}),
26+
});
27+
28+
// THEN
29+
Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', {
30+
DetectorModelDefinition: {
31+
States: [{
32+
OnEnter: {
33+
Events: [{
34+
Actions: [{
35+
ResetTimer: {
36+
TimerName: 'MyTimer',
37+
},
38+
}],
39+
}],
40+
},
41+
}],
42+
},
43+
});
44+
});

0 commit comments

Comments
 (0)