├── .github
├── ISSUE_TEMPLATE
│ └── bug_report.md
└── workflows
│ └── main.yml
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── aws-cert-converter.py
├── aws_credentials.h
├── demo_mqtt.cpp
├── demo_shadow.cpp
├── main.cpp
├── mbed-client-for-aws.lib
├── mbed-os.lib
├── mbed_app.json
├── resources
└── official_armmbed_example_badge.png
├── tests
├── README.md
└── aws.log
└── wifi-ism43362.lib
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: 'type: bug'
6 | assignees: ''
7 |
8 | ---
9 |
10 |
28 |
29 | ### Description of defect
30 |
31 |
35 |
36 |
37 | #### Target(s) affected by this defect ?
38 |
39 |
40 | #### Toolchain(s) (name and version) displaying this defect ?
41 |
42 |
43 | #### What version of Mbed-os are you using (tag or sha) ?
44 |
53 |
54 |
55 | #### What version(s) of tools are you using. List all that apply (E.g. mbed-cli)
56 |
57 |
58 | #### How is this defect reproduced ?
59 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build example application
2 |
3 | on:
4 | pull_request:
5 | push:
6 |
7 | jobs:
8 | build-cli-v1:
9 | container:
10 | image: ghcr.io/armmbed/mbed-os-env:master-latest
11 |
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | matrix:
16 | target: [K64F, DISCO_L475VG_IOT01A]
17 | profile: [release, debug, develop]
18 |
19 |
20 | steps:
21 | -
22 | name: Checkout
23 | uses: actions/checkout@v2
24 |
25 | -
26 | name: build-example
27 | run: |
28 | set -e
29 | mbed deploy
30 | mbed compile -t GCC_ARM -m ${{ matrix.target }} --profile ${{ matrix.profile }}
31 |
32 |
33 | build-cli-v2:
34 | container:
35 | image: ghcr.io/armmbed/mbed-os-env:master-latest
36 |
37 | runs-on: ubuntu-latest
38 |
39 | strategy:
40 | matrix:
41 | target: [K64F, DISCO_L475VG_IOT01A]
42 | profile: [release, debug, develop]
43 |
44 |
45 | steps:
46 | -
47 | name: Checkout
48 | uses: actions/checkout@v2
49 |
50 | -
51 | name: build-example-application
52 | run: |
53 | set -e
54 | mbed-tools deploy
55 | mbed-tools compile -t GCC_ARM -m ${{ matrix.target }} --profile ${{ matrix.profile }}
56 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2020 ARM Limited. All rights reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
5 |
6 | set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "")
7 | set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "")
8 | set(APP_TARGET mbed-os-example-for-aws)
9 |
10 | include(${MBED_PATH}/tools/cmake/app.cmake)
11 |
12 | project(${APP_TARGET})
13 |
14 | add_subdirectory(${MBED_PATH})
15 | add_subdirectory(mbed-client-for-aws)
16 |
17 | if("-DMBED_CONF_ISM43362_PROVIDE_DEFAULT=1" IN_LIST MBED_CONFIG_DEFINITIONS)
18 | add_subdirectory(wifi-ism43362)
19 | endif()
20 |
21 | add_executable(${APP_TARGET})
22 |
23 | mbed_configure_app_target(${APP_TARGET})
24 |
25 | target_include_directories(${APP_TARGET}
26 | PRIVATE
27 | .
28 | )
29 |
30 | target_sources(${APP_TARGET}
31 | PRIVATE
32 | main.cpp
33 | demo_mqtt.cpp
34 | demo_shadow.cpp
35 | )
36 |
37 | if("-DMBED_CONF_ISM43362_PROVIDE_DEFAULT=1" IN_LIST MBED_CONFIG_DEFINITIONS)
38 | target_link_libraries(${APP_TARGET}
39 | PRIVATE
40 | wifi-ism43362
41 | )
42 | endif()
43 |
44 | target_link_libraries(${APP_TARGET}
45 | PRIVATE
46 | mbed-os
47 | mbed-client-for-aws
48 | )
49 |
50 | mbed_set_post_build(${APP_TARGET})
51 |
52 | option(VERBOSE_BUILD "Have a verbose build process")
53 | if(VERBOSE_BUILD)
54 | set(CMAKE_VERBOSE_MAKEFILE ON)
55 | endif()
56 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Mbed OS
2 |
3 | Mbed OS is an open-source, device software platform for the Internet of Things. Contributions are an important part of the platform, and our goal is to make it as simple as possible to become a contributor.
4 |
5 | To encourage productive collaboration, as well as robust, consistent and maintainable code, we have a set of guidelines for [contributing to Mbed OS](https://os.mbed.com/docs/mbed-os/latest/contributing/index.html).
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Mbed OS example for AWS cloud
4 |
5 | The example project is part of the [Arm Mbed OS Official Examples](https://os.mbed.com/code/). It contains two demos:
6 | * MQTT (default): publishes a message every 1 second for 10 messages or until a message is received.
7 | * Device Shadow service: retrieves a desired value from the cloud, then reports a string value and then an integer value to the cloud.
8 |
9 | You can build the project with all supported [Mbed OS build tools](https://os.mbed.com/docs/mbed-os/latest/tools/index.html). However, this example project specifically refers to the command-line interface tool [Arm Mbed CLI](https://github.com/ARMmbed/mbed-cli#installing-mbed-cli).
10 | (Note: To see a rendered example you can import into the Arm Online Compiler, please see our [import quick start](https://os.mbed.com/docs/mbed-os/latest/quick-start/online-with-the-online-compiler.html#importing-the-code).)
11 |
12 | ## Mbed OS build tools
13 |
14 | ### Mbed CLI 2
15 | Starting with version 6.5, Mbed OS uses Mbed CLI 2. It uses Ninja as a build system, and CMake to generate the build environment and manage the build process in a compiler-independent manner. If you are working with Mbed OS version prior to 6.5 then check the section [Mbed CLI 1](#mbed-cli-1).
16 | 1. [Install Mbed CLI 2](https://os.mbed.com/docs/mbed-os/latest/build-tools/install-or-upgrade.html).
17 | 1. From the command-line, import the example: `mbed-tools import mbed-os-example-for-aws`
18 | 1. Change the current directory to where the project was imported.
19 |
20 | ### Mbed CLI 1
21 | 1. [Install Mbed CLI 1](https://os.mbed.com/docs/mbed-os/latest/quick-start/offline-with-mbed-cli.html).
22 | 1. From the command-line, import the example: `mbed import mbed-os-example-for-aws`
23 | 1. Change the current directory to where the project was imported.
24 |
25 | ## Configuring the AWS IoT Core service
26 |
27 | 1. Create an AWS account if you don't have one, and login to it.
28 |
29 | __NOTE:__ If you have an admin for your AWS account, please contact them to add a user to the account. You should obtain your login credentials from your admin in this case.
30 |
31 | 1. Set up device credentials and policy via the AWS IoT console. You can refer to the AWS documentation [here](https://docs.aws.amazon.com/iot/latest/developerguide/iot-gs.html). Follow the steps there to
32 |
33 | * create a thing
34 | * generate a device certificate and keys
35 | * create an IoT policy and attach that policy to your device.
36 |
37 | Also download "Amazon Root CA 1" from [here](https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html#server-authentication-certs).
38 |
39 | Once you have downloaded the credentials, you will need to place them in the [`aws_credentials.h`](./aws_credentials.h) file of this example.
40 |
41 | The example includes a python script to automate converting the credentials you downloaded from AWS into C-compatible arrays/strings. First, create a new folder in the project to store your credential files, eg: `mkdir aws-credentials`. Copy the previously-downloaded credential files into this subdirectory.
42 |
43 | Then, you can run the script to automatically generate the necessary code from the credentials:
44 |
45 | ```
46 | python aws-cert-converter.py aws-credentials
47 | ```
48 |
49 | For more details on how to use the convert script, simply pass in the `-h` flag to print the help documentation.
50 |
51 | The above command will read your credential files and place them into a C header file for you: `aws_credentials.h`
52 |
53 | 1. Once you have created the "thing", you will need to obtain the custom endpoint URL from the console. At the time of writing this document, you can find it under "Settings" in the IoT console.
54 |
55 | In [`mbed_app.json`](./mbed_app.json) file, set `aws-endpoint.value` to be that of the custom endpoint.
56 |
57 | 1. Set a topic that both your device and the cloud can publish messages to.
58 |
59 | In [`mbed_app.json`](./mbed_app.json) file, set `aws-mqtt-topic.value` to a name you prefer, or use the default one. On the AWS console, you will then need to subscribe to the same topic name. At the time of writing this document, you can find this under "Test" on the console.
60 |
61 | 1. Give your device a name by setting `aws-client-identifier` in [`mbed_app.json`](./mbed_app.json).
62 |
63 | ## Building and running
64 |
65 | ### MQTT demo (default)
66 |
67 | 1. If using WiFi (e.g. on DISCO_L475VG_IOT01A), enter your network's SSID and password in [`mbed_app.json`](./mbed_app.json) (see [here](https://github.com/ARMmbed/mbed-os-example-wifi/blob/master/README.md#getting-started)). Keep any existing `\"`s. (If you use a different WiFi-enabled target, you may need to manually import its WiFi driver as described [here](https://github.com/ARMmbed/mbed-os-example-wifi#supported-hardware).)
68 |
69 | 1. For Ethernet (e.g on K64F), connect a cable to the port.
70 |
71 | 1. Connect a USB cable between the USB port on the board and the host computer.
72 |
73 | 1. Run the following command to build the example project, program the microcontroller flash memory, and open a serial terminal:
74 |
75 | * Mbed CLI 2
76 |
77 | ```bash
78 | $ mbed-tools compile -m -t --flash --sterm --baudrate=115200
79 | ```
80 |
81 | * Mbed CLI 1
82 |
83 | ```bash
84 | $ mbed compile -m -t --flash --sterm --baudrate=115200
85 | ```
86 |
87 | Alternatively, you can manually copy the binary to the board, which you mount on the host computer over USB.
88 | The binary is located at:
89 | * **Mbed CLI 2** - `./cmake_build////mbed-os-example-for-aws.bin`
90 | * **Mbed CLI 1** - `./BUILD///mbed-os-example-for-aws.bin`
91 |
92 | Depending on the target, you can build the example project with the `GCC_ARM` or `ARM` toolchain. Run the command below to determine which toolchain supports your target:
93 |
94 | ```
95 | $ mbed compile -S
96 | ```
97 |
98 | ### Device Shadow demo
99 |
100 | Before running this demo, go to the AWS IoT Core console. In _Test_ -> _Subscribe to a topic_, subscribe to `$aws/things//shadow/#` (the `#` is a wildcard) on the AWS to monitor all Device Shadow updates. Then in _Publish to a topic_, publish to `$aws/things//shadow/update` the following payload:
101 |
102 | ```json
103 | {
104 | "state": {
105 | "desired": {
106 | "DemoNumber": 200
107 | }
108 | }
109 | }
110 | ```
111 |
112 | Build with the same steps as the MQTT demo, but also set `aws-client.shadow` to `true` in [`mbed_app.json`](./mbed_app.json) before compilation.
113 |
114 | ## Expected output
115 |
116 | ### MQTT demo (default)
117 |
118 | Once the example starts to run, you can [monitor a serial terminal](https://os.mbed.com/docs/mbed-os/v6.0/tutorials/serial-comm.html) to see that the device connects to your network, exchanges some TLS handshakes, connects to AWS and publishes to the topic you just subscribed. This can be seen on the AWS console as incoming messages.
119 |
120 | The application publishes a message every second for 10 seconds, or until it receives a message from the cloud:
121 | ```
122 | [INFO][Main]: Publishing "10 messages left to send, or until we receive a reply" to topic
123 | [INFO][Main]: Message sent successfully
124 | [INFO][Main]: Publishing "9 messages left to send, or until we receive a reply" to topic
125 | [INFO][Main]: Message sent successfully
126 | [INFO][Main]: Publishing "8 messages left to send, or until we receive a reply" to topic
127 | [INFO][Main]: Message sent successfully
128 | ```
129 |
130 | You can send a message to your device via the AWS IoT Core console (_Test_ -> _Publish to a topic_). Use the same topic name you set in `aws-mqtt-topic.value` in [`mbed_app.json`](./mbed_app.json). Use the existing JSON structure and set "message" to one you want to send.
131 |
132 | On receipt of a message, the application displays on the console the message you sent via the AWS IoT Core console.
133 |
134 | ### Device Shadow demo
135 |
136 | The following will be printed to the serial:
137 | ```
138 | [INFO][Main]: Device Shadow document downloaded
139 | [INFO][Main]: Desired value of DemoNumber:
140 | [INFO][Main]: Device Shadow reported string value published
141 | [INFO][Main]: Device Shadow reported integer value published
142 | ```
143 |
144 | ## Troubleshooting
145 | If you have problems, you can review the [documentation](https://os.mbed.com/docs/latest/tutorials/debugging.html) for suggestions on what could be wrong and how to fix it.
146 |
147 | ## Related Links
148 |
149 | * [Mbed client for AWS IoT Core](https://github.com/ARMmbed/mbed-client-for-aws)
150 | * [AWS IoT Core](https://aws.amazon.com/iot-core/)
151 | * [Mbed OS Configuration](https://os.mbed.com/docs/latest/reference/configuration.html).
152 | * [Mbed OS Serial Communication](https://os.mbed.com/docs/latest/tutorials/serial-communication.html).
153 | * [Mbed boards](https://os.mbed.com/platforms/).
154 |
155 | ### License and contributions
156 |
157 | The software is provided under Apache-2.0 license. Contributions to this project are accepted under the same license. Please see contributing.md for more info.
158 |
159 | This project contains code from other projects. The original license text is included in those source files. They must comply with our license guide.
160 |
--------------------------------------------------------------------------------
/aws-cert-converter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import argparse
4 | from os import walk
5 |
6 | # If modifying the template below,
7 | # make sure to double escape newlines you want in the C-string (ie: '\\n')
8 | # and to double-up brackets ('{' and '}' become '{{' and '}}') or else
9 | # formatting of the template string will fail
10 | header_template = (
11 | """
12 | // AWS Certificates
13 |
14 | #ifndef AWS_CREDENTIALS_H
15 | #define AWS_CREDENTIALS_H
16 |
17 | namespace aws {{
18 | namespace credentials {{
19 | /*
20 | * PEM-encoded root CA certificate
21 | */
22 | const char rootCA[] =
23 | {0};
24 |
25 | /*
26 | * PEM-encoded client certificate
27 | */
28 | const char clientCrt[] =
29 | {1};
30 |
31 | /*
32 | * PEM-encoded client private key.
33 | */
34 | const char clientKey[] =
35 | {2};
36 |
37 | }}
38 | }}
39 |
40 | #endif
41 | """
42 | )
43 |
44 | default_out_file_name = "aws_credentials.h"
45 |
46 | # Formats the given file into a C-string with newlines
47 | def format_file(file_path):
48 | out = ''
49 | with open(file_path, 'r') as f:
50 | lines = f.readlines()
51 | for l in lines:
52 | # Do not add a newline to the last line
53 | line_format = '"{}\\n"\n'
54 | if l is lines[-1]:
55 | line_format = '"{}"\n'
56 | out = out + line_format.format(l.strip())
57 | return out
58 |
59 | def main():
60 | parser = argparse.ArgumentParser(description='Convert AWS credential files to a compatible C-style header format')
61 | parser.add_argument('certs_directory', metavar='d', help='Path to directory containing credential files downloaded from AWS IoT Console')
62 | global default_out_file_name
63 | parser.add_argument('--output-file', help='Output file name (optional, defaults to: {}'.format(default_out_file_name))
64 | args = parser.parse_args()
65 |
66 | # Walk the given directory to find the cert files we need
67 | f = []
68 | for (dirpath, dirnames, filenames) in walk(args.certs_directory):
69 | f.extend(filenames)
70 | break
71 |
72 | # These are the files we need, make sure they exist
73 | root_ca_file = None
74 | client_crt_file = None
75 | client_key_file = None
76 | for cert_file in f:
77 | if "root" in cert_file.lower():
78 | root_ca_file = args.certs_directory + "/" + cert_file
79 | elif ".pem.crt" in cert_file:
80 | client_crt_file = args.certs_directory + "/" + cert_file
81 | elif "private.pem.key" in cert_file:
82 | client_key_file = args.certs_directory + "/" + cert_file
83 |
84 | if root_ca_file:
85 | print("Root CA file found: {}".format(root_ca_file))
86 | else:
87 | print("Could not find Root CA file (eg: AmazonRootCA1.pem)!")
88 | exit()
89 |
90 | if client_crt_file:
91 | print("Client certificate file found: {}".format(client_crt_file))
92 | else:
93 | print("Could not find client certificate file (eg: xxxxxxxxxx-certificate.pem.crt)!")
94 | exit()
95 |
96 | if client_key_file:
97 | print("Client key file found: {}".format(client_key_file))
98 | else:
99 | print("Could not find client private key file (eg: xxxxxxxxxx-private.pem.key)!")
100 | exit()
101 |
102 | print("Generating C-style header from given credentials...")
103 |
104 | global header_template
105 | out_file_name = default_out_file_name
106 | if args.output_file:
107 | out_file_name = args.output_file
108 |
109 | with open(out_file_name, 'w+') as out:
110 | out.write(header_template.format(format_file(root_ca_file),\
111 | format_file(client_crt_file),\
112 | format_file(client_key_file)))
113 |
114 | print("Saved generated credentials header to {}!".format(out_file_name))
115 |
116 | if __name__ == "__main__":
117 | main()
118 |
--------------------------------------------------------------------------------
/aws_credentials.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AWS Certificates
3 | * Copyright (c) 2020 Arm Limited
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 |
8 | #ifndef AWS_CREDENTIALS_H
9 | #define AWS_CREDENTIALS_H
10 |
11 | namespace aws {
12 | namespace credentials {
13 | /*
14 | * PEM-encoded root CA certificate
15 | *
16 | * Must include the PEM header and footer,
17 | * and every line of the body needs to be quoted and end with \n:
18 | * "-----BEGIN CERTIFICATE-----\n"
19 | * "...base64 data...\n"
20 | * "-----END CERTIFICATE-----";
21 | */
22 | const char rootCA[] = "-----BEGIN CERTIFICATE-----\n"
23 | "...\n"
24 | "...\n"
25 | "...\n"
26 | "-----END CERTIFICATE-----";
27 |
28 | /*
29 | * PEM-encoded client certificate
30 | *
31 | * Must include the PEM header and footer,
32 | * and every line of the body needs to be quoted and end with \n:
33 | * "-----BEGIN CERTIFICATE-----\n"
34 | * "...base64 data...\n"
35 | * "-----END CERTIFICATE-----";
36 | */
37 | const char clientCrt[] = "-----BEGIN CERTIFICATE-----\n"
38 | "...\n"
39 | "...\n"
40 | "...\n"
41 | "-----END CERTIFICATE-----";
42 |
43 | /*
44 | * PEM-encoded client private key.
45 | *
46 | * Must include the PEM header and footer,
47 | * and every line of the body needs to be quoted and end with \n:
48 | * "-----BEGIN RSA PRIVATE KEY-----\n"
49 | * "...base64 data...\n"
50 | * "-----END RSA PRIVATE KEY-----";
51 | */
52 | const char clientKey[] = "-----BEGIN RSA PRIVATE KEY-----\n"
53 | "...\n"
54 | "...\n"
55 | "...\n"
56 | "-----END RSA PRIVATE KEY-----";
57 |
58 | }
59 | }
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/demo_mqtt.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020-2021 Arm Limited
3 | * SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | #if !MBED_CONF_AWS_CLIENT_SHADOW
7 |
8 | #include "mbed.h"
9 | #include "mbed-trace/mbed_trace.h"
10 | #include "rtos/ThisThread.h"
11 | #include "AWSClient/AWSClient.h"
12 |
13 | extern "C" {
14 | #include "core_json.h"
15 | }
16 |
17 | #define TRACE_GROUP "Main"
18 |
19 | static bool reply_received = false;
20 |
21 | // Callback when a MQTT message has been added to the topic
22 | void on_message_callback(
23 | const char *topic,
24 | uint16_t topic_length,
25 | const void *payload,
26 | size_t payload_length)
27 | {
28 | char *json_value;
29 | size_t value_length;
30 | auto ret = JSON_Search((char *)payload, payload_length, "sender", strlen("sender"), &json_value, &value_length);
31 | if (ret == JSONSuccess && (strncmp(json_value, "device", strlen("device")) == 0)) {
32 | tr_info("Message sent successfully");
33 | } else {
34 | ret = JSON_Search((char *)payload, payload_length, "message", strlen("message"), &json_value, &value_length);
35 | if (ret == JSONSuccess) {
36 | reply_received = true;
37 | tr_info("Message received from the cloud: \"%.*s\"", value_length, json_value);
38 | } else {
39 | tr_error("Failed to extract message from the payload: \"%.*s\"", payload_length, (const char *) payload);
40 | }
41 | }
42 | }
43 |
44 | void demo()
45 | {
46 | AWSClient &client = AWSClient::getInstance();
47 |
48 | // Subscribe to the topic
49 | const char topic[] = MBED_CONF_APP_AWS_MQTT_TOPIC;
50 | int ret = client.subscribe(topic, strlen(topic));
51 | if (ret != MBED_SUCCESS) {
52 | tr_error("AWSClient::subscribe() failed");
53 | return;
54 | }
55 |
56 | // Send ten message to the cloud (one per second)
57 | // Stop when we receive a cloud-to-device message
58 | char payload[128];
59 | for (int i = 0; i < 10; i++) {
60 | if (reply_received) {
61 | // If we have received a message from the cloud, don't send more messeges
62 | break;
63 | }
64 |
65 | // The MQTT protocol does not distinguish between senders,
66 | // so we add a "sender" attribute to the payload
67 | const char base_message[] = "messages left to send, or until we receive a reply";
68 | sprintf(payload, "{\n"
69 | " \"sender\": \"device\",\n"
70 | " \"message\": \"%d %s\"\n"
71 | "}",
72 | 10 - i, base_message);
73 | tr_info("Publishing \"%d %s\" to topic \"%s\"", 10 - i, base_message, topic);
74 | ret = client.publish(
75 | topic,
76 | strlen(topic),
77 | payload,
78 | strlen(payload)
79 | );
80 | if (ret != MBED_SUCCESS) {
81 | tr_error("AWSClient::publish() failed");
82 | goto unsubscribe;
83 | }
84 |
85 | rtos::ThisThread::sleep_for(1s);
86 | }
87 |
88 | // If the user didn't manage to send a cloud-to-device message earlier,
89 | // let's wait until we receive one
90 | while (!reply_received) {
91 | // Continue to receive messages in the communication thread
92 | // which is internally created and maintained by the Azure SDK.
93 | sleep();
94 | }
95 |
96 | unsubscribe:
97 | // Unsubscribe from the topic
98 | ret = client.unsubscribe(topic, strlen(topic));
99 | if (ret != MBED_SUCCESS) {
100 | tr_error("AWSClient::unsubscribe() failed");
101 | }
102 | }
103 |
104 | #endif // !MBED_CONF_AWS_CLIENT_SHADOW
--------------------------------------------------------------------------------
/demo_shadow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020-2021 Arm Limited
3 | * SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | #if MBED_CONF_AWS_CLIENT_SHADOW
7 |
8 | #include "mbed.h"
9 | #include "mbed-trace/mbed_trace.h"
10 | #include "AWSClient/AWSClient.h"
11 |
12 | extern "C" {
13 | #include "core_json.h"
14 | }
15 |
16 | #define TRACE_GROUP "Main"
17 |
18 | // This should not be called for the Device Shadow demo -
19 | // Device Shadow messages are internally consumed by the client
20 | void on_message_callback(
21 | const char *topic,
22 | uint16_t topic_length,
23 | const void *payload,
24 | size_t payload_length)
25 | {
26 | tr_warning(
27 | "Message received on non-shadow topic: %.*s payload: %.*s",
28 | topic_length,
29 | topic,
30 | (const char *) payload_length,
31 | payload
32 | );
33 | }
34 |
35 | void demo()
36 | {
37 | AWSClient &client = AWSClient::getInstance();
38 |
39 | // Download shadow document
40 | auto ret = client.downloadShadowDocument();
41 | if (ret == MBED_SUCCESS) {
42 | tr_info("Device Shadow document downloaded");
43 | } else {
44 | tr_error("AWSClient::downloadShadowDocument() failed: %d", ret);
45 | return; // cannot continue without downloadShadowDocument()
46 | }
47 |
48 | // Get a desired shadow value
49 | const char shadow_demo_int_key[] = "DemoNumber";
50 | const int shadow_demo_int_value = 100;
51 | char *shadow_value;
52 | size_t shadow_value_length;
53 | ret = client.getShadowDesiredValue(
54 | shadow_demo_int_key,
55 | strlen(shadow_demo_int_key),
56 | &shadow_value,
57 | &shadow_value_length
58 | );
59 | if (ret == MBED_SUCCESS) {
60 | tr_info("Desired value of %s: %.*s", shadow_demo_int_key, shadow_value_length, shadow_value);
61 | } else {
62 | tr_error(
63 | "AWSClient::getShadowDesiredValue() failed: %d, "
64 | "please ensure you have set a desired value for %s (e.g. using the AWS Console)",
65 | ret,
66 | shadow_demo_int_key
67 | );
68 | }
69 |
70 | // Report a string shadow value
71 | const char shadow_demo_string_key[] = "DemoName";
72 | const char shadow_demo_string_value[] = "mbed-os-example-for-aws";
73 | ret = client.publishShadowReportedValue(
74 | shadow_demo_string_key,
75 | strlen(shadow_demo_string_key),
76 | shadow_demo_string_value,
77 | strlen(shadow_demo_string_value)
78 | );
79 | if (ret == MBED_SUCCESS) {
80 | tr_info("Device Shadow reported string value published");
81 | } else {
82 | tr_error("AWSClient::publishShadowReportedValue() failed: %d", ret);
83 | }
84 |
85 | // Report an integer shadow value
86 | ret = client.publishShadowReportedValue(
87 | shadow_demo_int_key,
88 | strlen(shadow_demo_int_key),
89 | shadow_demo_int_value
90 | );
91 | if (ret == MBED_SUCCESS) {
92 | tr_info("Device Shadow reported integer value published");
93 | } else {
94 | tr_error("AWSClient::publishShadowReportedValue() failed: %d", ret);
95 | }
96 | }
97 |
98 | #endif // MBED_CONF_AWS_CLIENT_SHADOW
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020-2021 Arm Limited
3 | * SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | #include "mbed.h"
7 | #include "mbed-trace/mbed_trace.h"
8 | #include "rtos/Mutex.h"
9 | #include "rtos/Thread.h"
10 | #include "rtos/ThisThread.h"
11 | #include "AWSClient/AWSClient.h"
12 | #include "aws_credentials.h"
13 |
14 | extern "C" {
15 | #include "core_json.h"
16 | }
17 |
18 | #define TRACE_GROUP "Main"
19 |
20 | // Implemented by the two demos
21 | void on_message_callback(
22 | const char *topic,
23 | uint16_t topic_length,
24 | const void *payload,
25 | size_t payload_length
26 | );
27 | void demo();
28 |
29 | rtos::Mutex connection_mutex;
30 |
31 | // Task to process MQTT responses at a regular interval
32 | static void process_responses()
33 | {
34 | AWSClient &client = AWSClient::getInstance();
35 | while (true) {
36 | connection_mutex.lock(); // avoid AWSClient::disconnect() while processing
37 | if (!client.isConnected()) {
38 | connection_mutex.unlock();
39 | break;
40 | }
41 | if (client.processResponses() != MBED_SUCCESS) {
42 | tr_error("AWSClient::processResponses() failed");
43 | }
44 | connection_mutex.unlock();
45 | rtos::ThisThread::sleep_for(10ms);
46 | }
47 | }
48 |
49 | int main()
50 | {
51 | // "goto" requires early initialization of variables
52 | AWSClient &client = AWSClient::getInstance();
53 | rtos::Thread process_thread;
54 | AWSClient::TLSCredentials_t credentials;
55 | int ret;
56 |
57 | mbed_trace_init();
58 | tr_info("Connecting to the network...");
59 | auto network = NetworkInterface::get_default_instance();
60 | if (network == NULL) {
61 | tr_error("No network interface found");
62 | goto end;
63 | }
64 | ret = network->connect();
65 | if (ret != 0) {
66 | tr_error("Connection error: %x", ret);
67 | goto end;
68 | }
69 | tr_info("MAC: %s", network->get_mac_address());
70 | tr_info("Connection Success");
71 |
72 | // Set credentials
73 | credentials.clientCrt = aws::credentials::clientCrt;
74 | credentials.clientCrtLen = sizeof(aws::credentials::clientCrt);
75 | credentials.clientKey = aws::credentials::clientKey;
76 | credentials.clientKeyLen = sizeof(aws::credentials::clientKey);
77 | credentials.rootCrtMain = aws::credentials::rootCA;
78 | credentials.rootCrtMainLen = sizeof(aws::credentials::rootCA);
79 |
80 | // Initialize client
81 | ret = client.init(
82 | on_message_callback,
83 | credentials
84 | );
85 | if (ret != MBED_SUCCESS) {
86 | tr_error("AWSClient::init() failed");
87 | goto disconnect;
88 | }
89 |
90 | // Connect to AWS IoT Core
91 | ret = client.connect(
92 | network,
93 | credentials,
94 | MBED_CONF_APP_AWS_ENDPOINT,
95 | MBED_CONF_APP_AWS_CLIENT_IDENTIFIER
96 | );
97 | if (ret != MBED_SUCCESS) {
98 | tr_error("AWSClient::connect() failed");
99 | goto disconnect;
100 | }
101 |
102 | // Start a background thread to process MQTT
103 | ret = process_thread.start(process_responses);
104 | if (ret != osOK) {
105 | tr_error("Failed to start thread to process MQTT");
106 | goto disconnect;
107 | }
108 |
109 | // Run a demo depending on the configuration in mbed_app.json:
110 | // * demo_mqtt.cpp if aws-client.shadow is unset or false
111 | // * demo_shadow.cpp if aws-client.shadow is true
112 | demo();
113 |
114 | disconnect:
115 | if (client.isConnected()) {
116 | connection_mutex.lock();
117 | ret = client.disconnect();
118 | connection_mutex.unlock();
119 | if (ret != MBED_SUCCESS) {
120 | tr_error("AWS::disconnect() failed");
121 | }
122 | }
123 |
124 | // The process thread should finish on disconnection
125 | ret = process_thread.join();
126 | if (ret != osOK) {
127 | tr_error("Failed to join thread");
128 | }
129 |
130 | ret = network->disconnect();
131 | if (ret != MBED_SUCCESS) {
132 | tr_error("NetworkInterface::disconnect() failed");
133 | }
134 |
135 | end:
136 | tr_info("End of the demo");
137 | }
--------------------------------------------------------------------------------
/mbed-client-for-aws.lib:
--------------------------------------------------------------------------------
1 | https://github.com/ARMmbed/mbed-client-for-aws.git/#f7f8ad1ed18f42f2da7b0c89f6d2e8803e985894
2 |
--------------------------------------------------------------------------------
/mbed-os.lib:
--------------------------------------------------------------------------------
1 | https://github.com/ARMmbed/mbed-os/#17dc3dc2e6e2817a8bd3df62f38583319f0e4fed
2 |
--------------------------------------------------------------------------------
/mbed_app.json:
--------------------------------------------------------------------------------
1 | {
2 | "config": {
3 | "aws-endpoint": {
4 | "help": "Endpoint URL",
5 | "value": "\"… .iot. … .amazonaws.com\""
6 | },
7 | "aws-mqtt-topic": {
8 | "help": "Topic to subscribe & publish to",
9 | "value": "\"sdkTest/sub\""
10 | },
11 | "aws-client-identifier": {
12 | "help": "Unique identifier for the thing",
13 | "value": "\"...\""
14 | }
15 | },
16 | "target_overrides": {
17 | "*": {
18 | "mbed-trace.enable": true,
19 | "mbed-trace.max-level": "TRACE_LEVEL_INFO",
20 | "platform.error-filename-capture-enabled": true,
21 | "platform.stdio-convert-newlines": true,
22 | "platform.stdio-baud-rate": 115200,
23 | "aws-client.shadow": false,
24 | "aws-client.aws-sdk-trace": false
25 | },
26 | "DISCO_L475VG_IOT01A": {
27 | "target.network-default-interface-type": "WIFI",
28 | "nsapi.default-wifi-security": "WPA_WPA2",
29 | "nsapi.default-wifi-ssid": "\"SSID\"",
30 | "nsapi.default-wifi-password": "\"PASSWORD\""
31 | },
32 | "EP_AGORA": {
33 | "platform.stdio-buffered-serial" : true,
34 | "platform.stdio-flush-at-exit" : true,
35 | "drivers.uart-serial-rxbuf-size" : 1024,
36 | "drivers.uart-serial-txbuf-size" : 1024,
37 | "lwip.ipv4-enabled" : true,
38 | "lwip.ipv6-enabled" : true,
39 | "lwip.ppp-enabled" : true,
40 | "lwip.tcp-enabled" : true,
41 | "lwip.ethernet-enabled" : false,
42 | "lwip.mem-size" : 22000,
43 | "lwip.tcpip-thread-stacksize" : 2000,
44 | "nsapi.dns-response-wait-time" : 30000,
45 | "nsapi.default-cellular-apn" : "\"phone\"",
46 | "lwip.use-mbed-trace" : true,
47 | "lwip.debug-enabled" : false
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/resources/official_armmbed_example_badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARMmbed/mbed-os-example-for-aws/fcabf3e5065e1989d3c9646607bbf994c24e7c51/resources/official_armmbed_example_badge.png
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | # Testing examples
2 |
3 | Examples are tested using tool [htrun](https://github.com/ARMmbed/mbed-os-tools/tree/master/packages/mbed-host-tests) and templated print log.
4 |
5 | To run the test, use following command after you build the example:
6 | ```
7 | mbedhtrun -d D: -p COM4 -m K64F -f .\BUILD\K64F\GCC_ARM\mbed-os-example-for-aws.bin --compare-log tests\aws.log --baud-rate=115200 --sync=0
8 | ```
9 |
10 |
11 | More details about `htrun` are [here](https://github.com/ARMmbed/mbed-os-tools/tree/master/packages/mbed-host-tests#testing-mbed-os-examples).
12 |
--------------------------------------------------------------------------------
/tests/aws.log:
--------------------------------------------------------------------------------
1 | Connecting to the network...
2 | Connection Success
3 | Certificate verification passed
4 | Message sent successfully
5 | Message received from the cloud
6 |
7 |
--------------------------------------------------------------------------------
/wifi-ism43362.lib:
--------------------------------------------------------------------------------
1 | https://github.com/ARMmbed/wifi-ism43362/#3813a4bb8623cc9b0525978748581f60d47142fa
2 |
--------------------------------------------------------------------------------