├── LICENSE
├── README.md
├── aws_button.png
├── aws_button_template.json
├── fs
└── init.js
└── mos.yml
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Cesanta Software Limited
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AWS IoT button example
2 |
3 | This is an Internet Button reference project: when a button on the device
4 | is pressed, a cloud backend gets a notification and performs an action.
5 | In this particular case, AWS Lambda function sends an email to the specific
6 | email address. But, again, the action could be anything.
7 |
8 | [](https://www.youtube.com/watch?v=yZ8VAxJ2XpA)
9 |
10 | ## Prerequisites
11 |
12 | - Hardware: ESP8266 NodeMCU
13 | - Amazon AWS account
14 | - Amazon's `aws` management tool (see https://aws.amazon.com/cli)
15 | - `mos` management tool installed
16 | (see [mos installation guide](https://mongoose-os.com/software.html))
17 |
18 | ## Architecture
19 |
20 |
21 |
22 |
23 |
24 | The data flow is as follows:
25 |
26 | - User presses the button
27 | - Device sends a message to the MQTT topic `DEVICE_ID/button_pressed`
28 | - AWS IoT receives the message and calls AWS Lambda Function
29 | - AWS Lambda Function publishes a message to the AWS SNS (Simple Notification Service)
30 | - AWS SNS notifies subscribers: in this case, just sends a message to a single email address
31 | - User receives the email
32 |
33 | ## Build instructions
34 |
35 | 1. Follow the [Cloud side setup](https://mongoose-os.com/aws-iot-starter-kit/#cloud) instructions to setup AWS CLI utility and your AWS credentials
36 | 2. Follow the [Device setup](https://mongoose-os.com/aws-iot-starter-kit/#dev) instructions to setup your device and provision it to the AWS IoT
37 | 3. Download [this repository as a zip file](https://github.com/mongoose-os-apps/aws-iot-button/archive/master.zip) and extract this app on your computer
38 | 4. Exit any running `mos.exe` process
39 | 5. Open a command prompt (on Windows) or terminal (on Mac/Linux) and go to the extracted app.
40 | 6. You should be able to see the `mos.yml` file by running `dir mos.yml` command (on Windows) or `ls -l mos.yml` (on Mac/Linux)
41 | 7. Find out your device ID
42 | ```
43 | mos config-get device.id
44 | ```
45 | On Windows, here and further, you might need to
46 | specify the full path to the `mos.exe` binary:
47 |
48 | ```
49 | c:\path\to\mos.exe config-get device.id
50 | ```
51 | 8. Run the following command to create AWS Cloud Formation stack.
52 | Change `$DEVICE_ID` to your actual device ID, and `$MY_EMAIL` to your email:
53 |
54 | ```
55 | aws cloudformation create-stack --stack-name my-internet-button --parameters ParameterKey=TopicName,ParameterValue=$DEVICE_ID/button_pressed ParameterKey=SubscriptionEmail,ParameterValue=$MY_EMAIL --capabilities CAPABILITY_IAM --template-body file://aws_button_template.json
56 | ```
57 |
58 | 9. Wait until the stack creation is completed (it may take a few minutes).
59 | Alternatively, you can use the web UI to check the status and read event
60 | details: https://console.aws.amazon.com/cloudformation/home
61 |
62 | 10. During the stack creation, AWS will send a Subscription Confirmation email,
63 | so check your email and confirm the subscription by following a link.
64 |
65 | 11. Run the following command to ensure that the stack creation is complete:
66 | ```
67 | aws cloudformation wait stack-create-complete --stack-name my-internet-button
68 | ```
69 |
70 | 11. Copy the `fs/init.js` file to your device:
71 | ```
72 | mos put fs/init.js
73 | ```
74 |
75 | 12. Attach to the device to see the device logs
76 | ```
77 | mos console
78 | ```
79 | 13. Reboot your device by pressing a reboot button
80 | 13. When the device is connected to the AWS IoT, push the "flash"
81 | button on your device.
82 | In the device's console, you'll see a message like this:
83 |
84 | ```
85 | Published: yes topic: esp8266_DA84C1/button_pressed message: {"free_ram":26824,"total_ram":44520}
86 | ```
87 |
88 | Now, check your email. It'll contain a new message:
89 |
90 | ```
91 | Button pressed: esp8266_DA84C1/button_pressed
92 | ```
93 |
94 | 14. Now you can go to your AWS dashboard and play with your stack.
95 | For example, you may add more subscriptions to the SNS: other than
96 | sending emails, it can also call some URL, send SMS, etc. And, of course,
97 | you can modify your lambda function to do whatever you want in response to
98 | the button press.
99 |
100 |
--------------------------------------------------------------------------------
/aws_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mongoose-os-apps/aws-iot-button/69df36586e3437203e0e968817651da8925788e5/aws_button.png
--------------------------------------------------------------------------------
/aws_button_template.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion": "2010-09-09",
3 | "Description": "Mongoose OS Internet Button Template",
4 | "Parameters": {
5 | "TopicName": {
6 | "Description": "IoT Topic Name",
7 | "Type": "String",
8 | "AllowedPattern": "[a-zA-Z0-9_/#+]*",
9 | "MinLength": "1",
10 | "MaxLength": "2048",
11 | "ConstraintDescription": "must contain only alphanumberic characters and underscores"
12 | },
13 | "SubscriptionEmail": {
14 | "Description": "Subscription Email",
15 | "Type": "String",
16 | "AllowedPattern": ".+",
17 | "MinLength": "1",
18 | "MaxLength": "2048"
19 | }
20 | },
21 | "Resources": {
22 | "mySNSTopic": {
23 | "Type": "AWS::SNS::Topic",
24 | "Properties": {
25 | "Subscription": [
26 | {
27 | "Protocol": "email",
28 | "Endpoint": {"Ref": "SubscriptionEmail"}
29 | }
30 | ]
31 | }
32 | },
33 | "myLambda": {
34 | "Type": "AWS::Lambda::Function",
35 | "Properties": {
36 | "Code": {
37 | "ZipFile": {
38 | "Fn::Join": ["\n", [
39 | "var AWS = require('aws-sdk');",
40 | "",
41 | "exports.handler = (event, context, callback) => {",
42 | {"Fn::Join": ["", [" var message = 'Button pressed: ", { "Ref": "TopicName" }, "';"]]},
43 | " var sns = new AWS.SNS();",
44 | " sns.publish({",
45 | {"Fn::Join": ["", [" TopicArn: '", { "Ref": "mySNSTopic" }, "',"]]},
46 | " Message: JSON.stringify(message)",
47 | " }, function(err, data) {",
48 | " if(err) {",
49 | " console.error('error publishing to SNS');",
50 | " context.fail(err);",
51 | " } else {",
52 | " console.info('message published to SNS');",
53 | " context.succeed();",
54 | " }",
55 | " });",
56 | "};",
57 | ""
58 | ]]
59 | }
60 | },
61 | "Handler": "index.handler",
62 | "Runtime": "nodejs4.3",
63 | "Role": {"Fn::GetAtt": ["myLambdaRoleWhichAllowsCallingSNS", "Arn"]}
64 | }
65 | },
66 | "myLambdaRoleWhichAllowsCallingSNS": {
67 | "Type": "AWS::IAM::Role",
68 | "Properties": {
69 | "AssumeRolePolicyDocument": {
70 | "Version" : "2012-10-17",
71 | "Statement": [ {
72 | "Effect": "Allow",
73 | "Principal": {
74 | "Service": [ "lambda.amazonaws.com" ]
75 | },
76 | "Action": [ "sts:AssumeRole" ]
77 | } ]
78 | },
79 | "Path": "/",
80 | "Policies": [
81 | {
82 | "PolicyName": "allow-call-sns",
83 | "PolicyDocument": {
84 | "Version" : "2012-10-17",
85 | "Statement": [ {
86 | "Effect": "Allow",
87 | "Action": "sns:Publish",
88 | "Resource": { "Ref": "mySNSTopic" }
89 | } ]
90 | }
91 | }
92 | ]
93 | }
94 | },
95 | "myTopicRule": {
96 | "Type": "AWS::IoT::TopicRule",
97 | "Properties": {
98 | "TopicRulePayload": {
99 | "RuleDisabled": "false",
100 | "Sql": {
101 | "Fn::Join" : [ "", ["SELECT * FROM '", { "Ref": "TopicName" }, "'"] ]
102 | },
103 | "Actions": [
104 | {
105 | "Lambda": {
106 | "FunctionArn": {"Fn::GetAtt": ["myLambda", "Arn"]}
107 | }
108 | }
109 | ]
110 | }
111 | }
112 | },
113 | "myPermissionForTopicRuleToInvokeLambda": {
114 | "Type": "AWS::Lambda::Permission",
115 | "Properties": {
116 | "Action": "lambda:InvokeFunction",
117 | "FunctionName": {"Fn::GetAtt": ["myLambda", "Arn"]},
118 | "Principal": "iot.amazonaws.com",
119 | "SourceAccount": {"Ref": "AWS::AccountId"},
120 | "SourceArn": {
121 | "Fn::Join": [
122 | "", [
123 | "arn:aws:iot:",
124 | { "Ref": "AWS::Region" },
125 | ":",
126 | { "Ref": "AWS::AccountId" },
127 | ":rule/",
128 | { "Ref": "myTopicRule" }
129 | ]
130 | ]
131 | }
132 | }
133 | }
134 | },
135 | "Outputs": {
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/fs/init.js:
--------------------------------------------------------------------------------
1 | // This example demonstrates how to react on a button press
2 | // by sending a message to AWS IoT.
3 | //
4 | // See README.md for details.
5 | //
6 | // Load Mongoose OS API
7 | load('api_gpio.js');
8 | load('api_mqtt.js');
9 | load('api_sys.js');
10 | load('api_config.js');
11 |
12 | let pin = 0; // GPIO 0 is typically a 'Flash' button
13 | GPIO.set_button_handler(pin, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 50, function(x) {
14 | let topic = Cfg.get('device.id') + '/button_pressed';
15 | let message = JSON.stringify({
16 | total_ram: Sys.total_ram(),
17 | free_ram: Sys.free_ram()
18 | });
19 | let ok = MQTT.pub(topic, message, 1);
20 | print('Published:', ok ? 'yes' : 'no', 'topic:', topic, 'message:', message);
21 | }, true);
22 |
23 | print('Flash button is configured on GPIO pin ', pin);
24 | print('Press the flash button now!');
25 |
--------------------------------------------------------------------------------
/mos.yml:
--------------------------------------------------------------------------------
1 | author: mongoose-os
2 | description: Internet button on AWS IoT
3 | # arch: PLATFORM
4 | version: 1.0
5 | manifest_version: 2017-05-18
6 |
7 | libs_version: ${mos.version}
8 | modules_version: ${mos.version}
9 | mongoose_os_version: ${mos.version}
10 |
11 | tags:
12 | - js
13 | - c
14 | - cloud
15 | - aws
16 |
17 | filesystem:
18 | - fs
19 |
20 | libs:
21 | # common mgos libs
22 | - origin: https://github.com/mongoose-os-libs/boards
23 | - origin: https://github.com/mongoose-os-libs/ca-bundle
24 | - origin: https://github.com/mongoose-os-libs/i2c
25 | - origin: https://github.com/mongoose-os-libs/rpc-service-config
26 | - origin: https://github.com/mongoose-os-libs/rpc-service-fs
27 | - origin: https://github.com/mongoose-os-libs/rpc-uart
28 | - origin: https://github.com/mongoose-os-libs/spi
29 |
30 | # libs necessary for the current app
31 | - origin: https://github.com/mongoose-os-libs/aws
32 | - origin: https://github.com/mongoose-os-libs/mjs
33 | - origin: https://github.com/mongoose-os-libs/wifi
34 |
--------------------------------------------------------------------------------