├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── amazon-kinesis-video-streams-workshop-jp ├── README.md └── lambda_function.py ├── aws-iot-core-raspberrypi-gpio ├── README.md └── main.py ├── aws-iot-events-for-beginners ├── README.md └── main.py └── aws-iot-greengrass-for-beginners ├── README.md ├── alert └── main.py ├── lambda └── lambda_function.py └── sensor └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AWS IoTサンプル集 2 | 3 | このリポジトリは、AWS IoTハンズオン、ワークショップで利用するサンプルプログラムを公開しています。 4 | 5 | 6 | ## License 7 | 8 | This library is licensed under the MIT-0 License. See the LICENSE file. 9 | 10 | -------------------------------------------------------------------------------- /amazon-kinesis-video-streams-workshop-jp/README.md: -------------------------------------------------------------------------------- 1 | # Amazon Kinesis Video Streams ハンズオン 2 | 3 | 本ディレクトリには、[Amazon Kinesis Video Streams ハンズオン](https://video-streaming-and-analysis.workshop.aws/) で利用するサンプルコードを置いております。 4 | 5 | ## 概要 6 | 7 | このハンズオンでは Amazon Kinesis Video Streams を用いたカメラデバイスからの動画の収集、保存、 ライブやオンデマンドでの再生、動画ファイルのダウンロード、 Amazon Rekognition Video と組み合わせたライブ顔認識やニアリアルタイム分析などを行う方法を学びます。 8 | 9 | ## コンテンツ 10 | 11 | - `lambda_function.py` 12 | - [Lab 2-3.](https://video-streaming-and-analysis.workshop.aws/lab-2/step-3.html#aws-lambda-にコードをアップロード) で作成する AWS Lambda のコードです。 13 | -------------------------------------------------------------------------------- /amazon-kinesis-video-streams-workshop-jp/lambda_function.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | import base64 5 | import datetime 6 | import json 7 | import logging 8 | import os 9 | import uuid 10 | 11 | import boto3 12 | import requests 13 | from requests_aws4auth import AWS4Auth 14 | 15 | 16 | logger = logging.getLogger(__name__) 17 | logger.setLevel(logging.DEBUG) 18 | 19 | # Get Elasticsearch service settings from environmental variables 20 | es_url = os.getenv("ES_URL") 21 | region = os.getenv("REGION") 22 | 23 | # Get credentials 24 | credentials = boto3.Session().get_credentials() 25 | aws_auth = AWS4Auth(credentials.access_key, credentials.secret_key, region, 'es', session_token=credentials.token) 26 | 27 | 28 | def process_record(record): 29 | """ Submit face recognition result to Elasticsearch service """ 30 | payload = json.loads(base64.b64decode(record['kinesis']['data'])) 31 | logger.info(f"record: {payload}") 32 | 33 | unix_time = payload["InputInformation"]["KinesisVideo"]["ServerTimestamp"] 34 | timestamp = datetime.datetime.utcfromtimestamp(unix_time).strftime("%Y-%m-%dT%H:%M:%S+0000") 35 | 36 | for face in payload["FaceSearchResponse"]: 37 | if not face["MatchedFaces"]: 38 | continue 39 | confidence = face["MatchedFaces"][0]["Similarity"] 40 | name = face["MatchedFaces"][0]["Face"]["ExternalImageId"] 41 | 42 | data = {"timestamp": timestamp, "name": name, "confidence": confidence} 43 | response = requests.post(f"{es_url}/record/face/{uuid.uuid4()}", 44 | auth=aws_auth, 45 | headers={"Content-Type": "application/json"}, 46 | data=json.dumps(data)) 47 | logger.info(f"result: code={response.status_code}, response={response.text}") 48 | 49 | 50 | def lambda_handler(event, context): 51 | for record in event['Records']: 52 | process_record(record) 53 | return {"result": "ok"} 54 | -------------------------------------------------------------------------------- /aws-iot-core-raspberrypi-gpio/README.md: -------------------------------------------------------------------------------- 1 | # Raspberry Pi and AWS IoT example 2 | 3 | ## 概要 4 | 5 | こちらは Raspberry Pi に接続したスイッチの状態を AWS IoT Core に送信するサンプルプログラムです。 6 | 7 | ## 必要なハードウェア 8 | 9 | - Raspberry Pi 3 Model B+ (およびmicroSD カード、電源ケーブル) 10 | - ブレッドボード 11 | - ジャンパーワイヤ 12 | - タクトスイッチ 13 | 14 | ## 事前準備 15 | 16 | - タクトスイッチを Raspberry Pi に接続します (片方を 3.3V, もう一方を GPIO に接続します) 17 | - microSD カードに Raspberry Pi OS を書き込み、ネットワークに接続できるようにしておきます 18 | - [AWS IoT Device SDK Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2) を Raspberry Pi にインストールします: `pip3 install awsiotsdk` 19 | - AWS IoT Core で発行したクライアント証明書・秘密鍵および、AWS IoT のルートCA証明書を Raspberry Pi にダウンロードしておきます 20 | - `main.py` の27行目, 44〜47行目の設定をご自身の環境に合わせて修正します 21 | -------------------------------------------------------------------------------- /aws-iot-core-raspberrypi-gpio/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # SPDX-License-Identifier: MIT-0 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this 7 | # software and associated documentation files (the "Software"), to deal in the Software 8 | # without restriction, including without limitation the rights to use, copy, modify, 9 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 10 | # permit persons to whom the Software is furnished to do so. 11 | # 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 14 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 15 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 16 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 17 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | # 19 | 20 | import json 21 | import time 22 | 23 | import RPi.GPIO as GPIO 24 | from awscrt import io, mqtt 25 | from awsiot import mqtt_connection_builder 26 | 27 | PIN = 24 28 | GPIO.setmode(GPIO.BCM) 29 | GPIO.setup(PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 30 | 31 | 32 | def read_switch(): 33 | """ return True if switch is pressed """ 34 | switch_pressed = GPIO.input(PIN) == GPIO.HIGH 35 | return switch_pressed 36 | 37 | 38 | def main(): 39 | event_loop_group = io.EventLoopGroup(1) 40 | host_resolver = io.DefaultHostResolver(event_loop_group) 41 | client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver) 42 | 43 | mqtt_connection = mqtt_connection_builder.mtls_from_path( 44 | endpoint="xxxxxxxxxxx-ats.iot.region.amazonaws.com", 45 | cert_filepath="xxxxxxxxxx-certificate.pem.crt", 46 | pri_key_filepath="xxxxxxxxxx-private.pem.key", 47 | ca_filepath="AmazonRootCA1.pem", 48 | client_id="raspi_switch", 49 | client_bootstrap=client_bootstrap, 50 | ) 51 | 52 | # Connect to AWS IoT 53 | connect_future = mqtt_connection.connect() 54 | connect_future.result() 55 | print("Connected!") 56 | 57 | # Read the switch state and publish a message 58 | last_state = False 59 | while True: 60 | switch_pressed = read_switch() 61 | if switch_pressed != last_state: 62 | print(f"pressed: {switch_pressed}") 63 | msg = {"pressed": switch_pressed} 64 | mqtt_connection.publish( 65 | topic="data/raspi_switch", 66 | payload=json.dumps(msg), 67 | qos=mqtt.QoS.AT_LEAST_ONCE) 68 | last_state = switch_pressed 69 | time.sleep(0.01) 70 | 71 | 72 | if __name__ == '__main__': 73 | main() 74 | -------------------------------------------------------------------------------- /aws-iot-events-for-beginners/README.md: -------------------------------------------------------------------------------- 1 | # AWS IoT Events初級ハンズオン 2 | 3 | 本ディレクトリには、[AWS IoT Events初級ハンズオン](https://aws-iot-events-for-beginners.workshop.aws/) で利用するサンプルコードを置いております。 4 | 5 | ## 概要 6 | 7 | このハンズオンでは AWS IoT Eventsの基本的な設定や、他のAWSサービスとの連携について学びます。 8 | 9 | 10 | ## コンテンツ 11 | 12 | - main.py 13 | - ダミーデータを送るためのサンプルプログラム 14 | -------------------------------------------------------------------------------- /aws-iot-events-for-beginners/main.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | from __future__ import absolute_import 4 | from __future__ import print_function 5 | 6 | import argparse 7 | import json 8 | import logging 9 | import os 10 | import random 11 | import signal 12 | import sys 13 | import time 14 | import traceback 15 | from datetime import datetime 16 | 17 | from awscrt import io, mqtt 18 | from awsiot import mqtt_connection_builder 19 | 20 | # - Overview - 21 | # This sample shows 1) how to connect AWS IoT Core. 2) How to publish 22 | 23 | BASE_TOPIC = "data/" 24 | DEFAULT_WAIT_TIME = 5 25 | KEEPALIVE = 300 26 | 27 | mqtt_connection = None 28 | device_name = None 29 | 30 | logger = logging.getLogger() 31 | handler = logging.StreamHandler(sys.stdout) 32 | logger.addHandler(handler) 33 | logger.setLevel(logging.INFO) 34 | logging.basicConfig() 35 | 36 | 37 | def arg_check(): 38 | """ 39 | argument check 40 | """ 41 | 42 | logging.debug("start: arg_check") 43 | parser = argparse.ArgumentParser() 44 | parser.add_argument("--device_name", required=True, 45 | help="[Must], input config file. include path") 46 | parser.add_argument("--endpoint", required=True, 47 | help="[Must], AWS IoT endpoint URI") 48 | parser.add_argument("--root_ca", required=False, 49 | help="root ca file name with path") 50 | parser.add_argument("--cert", required=False, 51 | help="device cert file name with path") 52 | parser.add_argument("--private", required=False, 53 | help="private cert key file name with path") 54 | parser.add_argument('--verbosity', choices=[x.name for x in io.LogLevel], 55 | default=io.LogLevel.NoLogs.name, help='Logging level') 56 | 57 | args = parser.parse_args() 58 | 59 | log_level = getattr(io.LogLevel, args.verbosity, "error") 60 | io.init_logging(log_level, 'stderr') 61 | loglevel_map = [ 62 | logging.INFO, logging.INFO, logging.INFO, 63 | logging.INFO, logging.INFO, logging.DEBUG, 64 | logging.DEBUG] 65 | logger.setLevel(loglevel_map[log_level]) 66 | logging.basicConfig() 67 | 68 | cert_list = find_certs_file() 69 | if args.root_ca is not None: 70 | cert_list[0] = args.root_ca 71 | if args.private is not None: 72 | cert_list[1] = args.private 73 | if args.cert is not None: 74 | cert_list[2] = args.cert 75 | 76 | logging.debug(cert_list) 77 | file_exist_check(cert_list) 78 | 79 | init_dict = { 80 | "device_name": args.device_name, 81 | "endpoint": args.endpoint, 82 | "certs": cert_list 83 | } 84 | return init_dict 85 | 86 | 87 | def file_exist_check(cert_list): 88 | """ 89 | Check the files exists 90 | all certs must placed in ./certs directory 91 | 92 | Parameters 93 | ---------- 94 | cert_list: Array 95 | """ 96 | 97 | for file in cert_list: 98 | if not os.path.exists(file): 99 | # if file not found, raise 100 | logger.error("cert file not found:%s", file) 101 | raise RuntimeError("file_not_exists") 102 | 103 | 104 | def find_certs_file(): 105 | """ 106 | Find the certificates file from ./certs directory 107 | 108 | Returns 109 | ---------- 110 | file_list: Array 111 | 0: Root CA Cert, 1: private key, 2: certificate 112 | """ 113 | 114 | certs_dir = "./certs" 115 | file_list = ["AmazonRootCA1.pem", "private.pem", "certificate.crt"] 116 | for _, _, names in os.walk(certs_dir): 117 | for file in names: 118 | if "AmazonRootCA1.pem" in file: 119 | file_list[0] = certs_dir + "/" + file 120 | elif "private" in file: 121 | file_list[1] = certs_dir + "/" + file 122 | elif "cert" in file: 123 | file_list[2] = certs_dir + "/" + file 124 | 125 | return file_list 126 | 127 | def device_main(): 128 | """ 129 | main loop for dummy device 130 | """ 131 | global device_name, mqtt_connection 132 | 133 | init_info = arg_check() 134 | device_name = init_info['device_name'] 135 | iot_endpoint = init_info['endpoint'] 136 | rootca_file = init_info['certs'][0] 137 | private_key_file = init_info['certs'][1] 138 | certificate_file = init_info['certs'][2] 139 | 140 | logger.info("device_name: %s", device_name) 141 | logger.info("endpoint: %s", iot_endpoint) 142 | logger.info("rootca cert: %s", rootca_file) 143 | logger.info("private key: %s", private_key_file) 144 | logger.info("certificate: %s", certificate_file) 145 | 146 | # Spin up resources 147 | event_loop_group = io.EventLoopGroup(1) 148 | host_resolver = io.DefaultHostResolver(event_loop_group) 149 | client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver) 150 | 151 | mqtt_connection = mqtt_connection_builder.mtls_from_path( 152 | endpoint=iot_endpoint, 153 | cert_filepath=certificate_file, 154 | pri_key_filepath=private_key_file, 155 | client_bootstrap=client_bootstrap, 156 | ca_filepath=rootca_file, 157 | client_id=device_name, 158 | clean_session=False, 159 | keep_alive_secs=KEEPALIVE) 160 | 161 | connected_future = mqtt_connection.connect() 162 | 163 | # Start sending dummy data 164 | topic = BASE_TOPIC + device_name 165 | logging.info("topic: %s", topic) 166 | while True: 167 | now = datetime.now().strftime('%Y-%m-%dT%H:%M:%S') 168 | tmp = 20 + random.randint(-5, 5) 169 | payload = {"DEVICENAME": device_name, "TIMESTAMP": now, "VALUE": tmp} 170 | logger.debug(" payload: %s", payload) 171 | 172 | mqtt_connection.publish( 173 | topic=topic, 174 | payload=json.dumps(payload), 175 | qos=mqtt.QoS.AT_LEAST_ONCE) 176 | 177 | time.sleep(DEFAULT_WAIT_TIME) 178 | 179 | 180 | def exit_sample(msg_or_exception): 181 | """ 182 | Exit sample with cleaning 183 | 184 | Parameters 185 | ---------- 186 | msg_or_exception: str or Exception 187 | """ 188 | if isinstance(msg_or_exception, Exception): 189 | logger.error("Exiting sample due to exception.") 190 | traceback.print_exception(msg_or_exception.__class__, msg_or_exception, sys.exc_info()[2]) 191 | else: 192 | logger.info("Exiting: %s", msg_or_exception) 193 | 194 | if not mqtt_connection: 195 | logger.info("Disconnecting...") 196 | mqtt_connection.disconnect() 197 | sys.exit(0) 198 | 199 | 200 | def exit_handler(_signal, frame): 201 | """ 202 | Exit sample 203 | """ 204 | exit_sample(" Key abort") 205 | 206 | 207 | if __name__ == "__main__": 208 | signal.signal(signal.SIGINT, exit_handler) 209 | 210 | device_main() 211 | -------------------------------------------------------------------------------- /aws-iot-greengrass-for-beginners/README.md: -------------------------------------------------------------------------------- 1 | # AWS IoT Greengrass入門ハンズオン 2 | 3 | 本ディレクトリには、[AWS IoT Greengrass入門ハンズオン](https://aws-iot-greengrass-for-beginners.workshop.aws/) で利用するサンプルコードを置いております。 4 | 5 | ## 概要 6 | 7 | このハンズオンでは AWS IoT Greengrassの基本的な設定や、デバイスとのメッセージングについて行う方法を学びます。 8 | 9 | ## コンテンツ 10 | 11 | - sensor 12 | - 「センサーデバイスの作成」で設定するAWS IoT Greengrassと繋がるThingのサンプル 13 | - lambda 14 | - 「デバイス同士のメッセージング」で設定する、AWS IoT Greengrass上にデプロイするLambda関数のサンプル 15 | - alert 16 | - 「デバイス同士のメッセージング」で設定する、AWS IoT Greengrassと繋がるThingのサンプル -------------------------------------------------------------------------------- /aws-iot-greengrass-for-beginners/alert/main.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | import argparse 5 | import time 6 | import logging 7 | import os 8 | import signal 9 | import sys 10 | import traceback 11 | from datetime import datetime 12 | from awscrt import io 13 | from awscrt.io import LogLevel 14 | from awscrt.mqtt import QoS, ConnectReturnCode 15 | from awsiot.greengrass_discovery import DiscoveryClient 16 | from awsiot import mqtt_connection_builder 17 | 18 | 19 | APP_ROOT = os.path.dirname(os.path.abspath(__file__)) + "/" 20 | CERT_ROOT = APP_ROOT + "certs/" 21 | GROUP_CA_FILE = CERT_ROOT + "group_ca.pem" 22 | 23 | private_key_path = None 24 | certtificate_path = None 25 | root_ca_path = None 26 | device_name = None 27 | region = None 28 | mqtt_connection = None 29 | 30 | logger = logging.getLogger() 31 | handler = logging.StreamHandler(sys.stdout) 32 | logger.addHandler(handler) 33 | logger.setLevel(logging.INFO) 34 | logging.basicConfig() 35 | 36 | 37 | def find_cert_file(cert_prefix): 38 | """ 39 | Find the certificates file from ./certs directory 40 | 41 | Parameters 42 | ---------- 43 | cert_prefix: AmazonRootCA1.pem, cert.pem, private.key 44 | 45 | Returns 46 | ---------- 47 | file_path: String 48 | 49 | """ 50 | 51 | for _, _, names in os.walk(CERT_ROOT): 52 | for file in names: 53 | if cert_prefix in file: 54 | return CERT_ROOT + "/" + file 55 | 56 | raise Exception("%s not found." % cert_prefix) 57 | 58 | 59 | def arg_check(): 60 | """ 61 | argument check 62 | """ 63 | global private_key_path, certtificate_path, root_ca_path, device_name, region 64 | 65 | parser = argparse.ArgumentParser() 66 | parser.add_argument( 67 | '-n', 68 | '--thing-name', 69 | action='store', 70 | required=True, 71 | dest='thing_name', 72 | help='Targeted thing name') 73 | parser.add_argument( 74 | '--region', 75 | action='store', 76 | dest='region', 77 | default='ap-northeast-1') 78 | parser.add_argument('-v', '--verbosity', choices=[x.name for x in LogLevel], default=LogLevel.NoLogs.name, 79 | help='Logging level') 80 | 81 | args = parser.parse_args() 82 | 83 | log_level = getattr(io.LogLevel, args.verbosity, "error") 84 | io.init_logging(log_level, 'stderr') 85 | loglevel_map = [ 86 | logging.INFO, logging.INFO, logging.INFO, 87 | logging.INFO, logging.INFO, logging.DEBUG, 88 | logging.DEBUG] 89 | logger.setLevel(loglevel_map[log_level]) 90 | logging.basicConfig() 91 | 92 | private_key_path = find_cert_file("private.key") 93 | certtificate_path = find_cert_file("cert.pem") 94 | root_ca_path = find_cert_file("AmazonRootCA1.pem") 95 | device_name = args.thing_name 96 | region = args.region 97 | 98 | 99 | def discover_gg_host(): 100 | 101 | event_loop_group = io.EventLoopGroup(1) 102 | host_resolver = io.DefaultHostResolver(event_loop_group) 103 | client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver) 104 | 105 | tls_options = io.TlsContextOptions.create_client_with_mtls_from_path( 106 | certtificate_path, private_key_path) 107 | #tls_options.override_default_trust_store_from_path(None, root_ca_path) 108 | tls_context = io.ClientTlsContext(tls_options) 109 | 110 | socket_options = io.SocketOptions() 111 | socket_options.connect_timeout_ms = 3000 112 | 113 | logger.info('Performing greengrass discovery...') 114 | discovery_client = DiscoveryClient( 115 | client_bootstrap, socket_options, tls_context, region) 116 | resp_future = discovery_client.discover(device_name) 117 | discover_response = resp_future.result() 118 | 119 | logger.debug(discover_response) 120 | 121 | for gg_group in discover_response.gg_groups: 122 | for gg_core in gg_group.cores: 123 | for connectivity_info in gg_core.connectivity: 124 | try: 125 | print( 126 | 'Trying core {} at host {} port {}'.format( 127 | gg_core.thing_arn, 128 | connectivity_info.host_address, 129 | connectivity_info.port)) 130 | connection = mqtt_connection_builder.mtls_from_path( 131 | endpoint=connectivity_info.host_address, 132 | port=connectivity_info.port, 133 | cert_filepath=certtificate_path, 134 | pri_key_filepath=private_key_path, 135 | client_bootstrap=client_bootstrap, 136 | ca_bytes=gg_group.certificate_authorities[0].encode( 137 | 'utf-8'), 138 | on_connection_interrupted=on_connection_interupted, 139 | on_connection_resumed=on_connection_resumed, 140 | client_id=device_name, 141 | clean_session=False, 142 | keep_alive_secs=6) 143 | 144 | connect_future = connection.connect() 145 | connect_future.result() 146 | print('Connected!') 147 | 148 | return connection 149 | 150 | except Exception as e: 151 | print('Connection failed with exception {}'.format(e)) 152 | continue 153 | 154 | sys.exit('All connection attempts failed') 155 | 156 | 157 | def on_connection_interupted(connection, error, **kwargs): 158 | logger.info('connection interrupted with error {}' % error) 159 | 160 | 161 | # Callback when an interrupted connection is re-established. 162 | def on_connection_resumed(connection, return_code, session_present, **kwargs): 163 | print( 164 | "Connection resumed. return_code: {} session_present: {}".format( 165 | return_code, 166 | session_present)) 167 | 168 | if return_code == ConnectReturnCode.ACCEPTED and not session_present: 169 | print("Session did not persist. Resubscribing to existing topics...") 170 | resubscribe_future, _ = connection.resubscribe_existing_topics() 171 | 172 | # Cannot synchronously wait for resubscribe result because we're on the connection's event-loop thread, 173 | # evaluate result with a callback instead. 174 | resubscribe_future.add_done_callback(on_resubscribe_complete) 175 | 176 | 177 | def on_resubscribe_complete(resubscribe_future): 178 | resubscribe_results = resubscribe_future.result() 179 | print("Resubscribe results: {}".format(resubscribe_results)) 180 | 181 | for topic, qos in resubscribe_results['topics']: 182 | if qos is None: 183 | sys.exit("Server rejected resubscribe to topic: {}".format(topic)) 184 | 185 | 186 | def on_message_received(topic, payload, **kwargs): 187 | print("Alert!! Received message from topic '{}': {}".format(topic, payload)) 188 | 189 | 190 | def device_main(): 191 | """ 192 | main loop for Alert device 193 | """ 194 | global device_name, mqtt_connection 195 | 196 | arg_check() 197 | 198 | mqtt_connection = discover_gg_host() 199 | topic = "alert/#" 200 | subscribe_future, _ = mqtt_connection.subscribe( 201 | topic, QoS.AT_MOST_ONCE, on_message_received) 202 | subscribe_result = subscribe_future.result() 203 | print("Subscribed to {} with {}".format( 204 | topic, str(subscribe_result['qos']))) 205 | 206 | while True: 207 | # eait for events 208 | time.sleep(1) 209 | 210 | 211 | def exit_sample(msg_or_exception): 212 | """ 213 | Exit sample with cleaning 214 | 215 | Parameters 216 | ---------- 217 | msg_or_exception: str or Exception 218 | """ 219 | global mqtt_connection 220 | 221 | if isinstance(msg_or_exception, Exception): 222 | logger.error("Exiting sample due to exception.") 223 | traceback.print_exception( 224 | msg_or_exception.__class__, 225 | msg_or_exception, 226 | sys.exc_info()[2]) 227 | else: 228 | logger.info("Exiting: %s", msg_or_exception) 229 | 230 | if not mqtt_connection: 231 | logger.info("Disconnecting...") 232 | mqtt_connection.disconnect() 233 | sys.exit(0) 234 | 235 | 236 | def exit_handler(_signal, frame): 237 | """ 238 | Exit sample 239 | """ 240 | exit_sample(" Key abort") 241 | 242 | 243 | if __name__ == "__main__": 244 | signal.signal(signal.SIGINT, exit_handler) 245 | 246 | device_main() -------------------------------------------------------------------------------- /aws-iot-greengrass-for-beginners/lambda/lambda_function.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | import greengrasssdk 5 | import json 6 | import logging 7 | import sys 8 | import os 9 | 10 | VALUE = os.environ.get('VALUE', '0.3') 11 | 12 | # Setup logging to stdout 13 | logger = logging.getLogger(__name__) 14 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 15 | 16 | # Creating a greengrass core sdk client 17 | client = greengrasssdk.client("iot-data") 18 | 19 | def lambda_handler(event, context): 20 | logging.info(event) 21 | if float(event["value"]) > float(VALUE): 22 | client.publish( 23 | topic="alert/world", 24 | payload=json.dumps({"status": "alert", "value": event["value"]}) 25 | ) 26 | logging.warning("published alert") -------------------------------------------------------------------------------- /aws-iot-greengrass-for-beginners/sensor/main.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | import argparse 5 | import time 6 | import json 7 | import logging 8 | import os 9 | import signal 10 | import sys 11 | import traceback 12 | from datetime import datetime 13 | from awscrt import io 14 | from awscrt.io import LogLevel 15 | from awscrt.mqtt import QoS 16 | from awsiot.greengrass_discovery import DiscoveryClient 17 | from awsiot import mqtt_connection_builder 18 | 19 | 20 | APP_ROOT = os.path.dirname(os.path.abspath(__file__)) + "/" 21 | CERT_ROOT = APP_ROOT + "certs/" 22 | GROUP_CA_FILE = CERT_ROOT + "group_ca.pem" 23 | 24 | private_key_path = None 25 | certificate_path = None 26 | root_ca_path = None 27 | device_name = None 28 | region = None 29 | mqtt_connection = None 30 | 31 | logger = logging.getLogger() 32 | handler = logging.StreamHandler(sys.stdout) 33 | logger.addHandler(handler) 34 | logger.setLevel(logging.INFO) 35 | logging.basicConfig() 36 | 37 | 38 | def find_cert_file(cert_prefix): 39 | """ 40 | Find the certificates file from ./certs directory 41 | 42 | Parameters 43 | ---------- 44 | cert_prefix: AmazonRootCA1.pem, cert.pem, private.key 45 | 46 | Returns 47 | ---------- 48 | file_path: String 49 | 50 | """ 51 | 52 | for _, _, names in os.walk(CERT_ROOT): 53 | for file in names: 54 | if cert_prefix in file: 55 | return CERT_ROOT + "/" + file 56 | 57 | raise Exception("%s not found." % cert_prefix) 58 | 59 | 60 | def arg_check(): 61 | """ 62 | argument check 63 | """ 64 | global private_key_path, certificate_path, root_ca_path, device_name, region 65 | 66 | parser = argparse.ArgumentParser() 67 | parser.add_argument( 68 | '-n', 69 | '--thing-name', 70 | action='store', 71 | required=True, 72 | dest='thing_name', 73 | help='Targeted thing name') 74 | parser.add_argument( 75 | '--region', 76 | action='store', 77 | dest='region', 78 | default='ap-northeast-1') 79 | parser.add_argument('-v', '--verbosity', choices=[x.name for x in LogLevel], default=LogLevel.NoLogs.name, 80 | help='Logging level') 81 | 82 | args = parser.parse_args() 83 | 84 | log_level = getattr(io.LogLevel, args.verbosity, "error") 85 | io.init_logging(log_level, 'stderr') 86 | loglevel_map = [ 87 | logging.INFO, logging.INFO, logging.INFO, 88 | logging.INFO, logging.INFO, logging.DEBUG, 89 | logging.DEBUG] 90 | logger.setLevel(loglevel_map[log_level]) 91 | logging.basicConfig() 92 | 93 | private_key_path = find_cert_file("private.key") 94 | certificate_path = find_cert_file("cert.pem") 95 | root_ca_path = find_cert_file("AmazonRootCA1.pem") 96 | device_name = args.thing_name 97 | region = args.region 98 | 99 | 100 | def discover_gg_host(): 101 | 102 | event_loop_group = io.EventLoopGroup(1) 103 | host_resolver = io.DefaultHostResolver(event_loop_group) 104 | client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver) 105 | 106 | tls_options = io.TlsContextOptions.create_client_with_mtls_from_path( 107 | certificate_path, private_key_path) 108 | #tls_options.override_default_trust_store_from_path(None, root_ca_path) 109 | tls_context = io.ClientTlsContext(tls_options) 110 | 111 | socket_options = io.SocketOptions() 112 | socket_options.connect_timeout_ms = 3000 113 | 114 | logger.info('Performing greengrass discovery...') 115 | discovery_client = DiscoveryClient( 116 | client_bootstrap, socket_options, tls_context, region) 117 | resp_future = discovery_client.discover(device_name) 118 | discover_response = resp_future.result() 119 | 120 | logger.debug(discover_response) 121 | 122 | for gg_group in discover_response.gg_groups: 123 | for gg_core in gg_group.cores: 124 | for connectivity_info in gg_core.connectivity: 125 | try: 126 | print( 127 | 'Trying core {} at host {} port {}'.format( 128 | gg_core.thing_arn, 129 | connectivity_info.host_address, 130 | connectivity_info.port)) 131 | connection = mqtt_connection_builder.mtls_from_path( 132 | endpoint=connectivity_info.host_address, 133 | port=connectivity_info.port, 134 | cert_filepath=certificate_path, 135 | pri_key_filepath=private_key_path, 136 | client_bootstrap=client_bootstrap, 137 | ca_bytes=gg_group.certificate_authorities[0].encode( 138 | 'utf-8'), 139 | on_connection_interrupted=on_connection_interupted, 140 | on_connection_resumed=on_connection_resumed, 141 | client_id=device_name, 142 | clean_session=False, 143 | keep_alive_secs=6) 144 | 145 | connect_future = connection.connect() 146 | connect_future.result() 147 | print('Connected!') 148 | 149 | return connection 150 | 151 | except Exception as e: 152 | print('Connection failed with exception {}'.format(e)) 153 | continue 154 | 155 | sys.exit('All connection attempts failed') 156 | 157 | 158 | def on_connection_interupted(connection, error, **kwargs): 159 | logger.info('connection interrupted with error {}' % error) 160 | 161 | 162 | def on_connection_resumed(connection, return_code, session_present, **kwargs): 163 | logger.info( 164 | 'connection resumed with return code {}, session present {}'.format( 165 | return_code, 166 | session_present)) 167 | 168 | 169 | def device_main(): 170 | """ 171 | main loop for Sensor device 172 | """ 173 | global device_name, mqtt_connection 174 | 175 | arg_check() 176 | 177 | mqtt_connection = discover_gg_host() 178 | 179 | while True: 180 | message = {} 181 | message['value'] = os.getloadavg()[1] 182 | message['timestamp'] = datetime.now().strftime('%Y-%m-%dT%H:%M:%S') 183 | message_json = json.dumps(message) 184 | topic = "data/" + device_name 185 | pub_future, _ = mqtt_connection.publish( 186 | topic, message_json, QoS.AT_MOST_ONCE) 187 | pub_future.result() 188 | print('Published topic {}: {}\n'.format(topic, message_json)) 189 | 190 | time.sleep(2) 191 | 192 | 193 | def exit_sample(msg_or_exception): 194 | """ 195 | Exit sample with cleaning 196 | 197 | Parameters 198 | ---------- 199 | msg_or_exception: str or Exception 200 | """ 201 | global mqtt_connection 202 | 203 | if isinstance(msg_or_exception, Exception): 204 | logger.error("Exiting sample due to exception.") 205 | traceback.print_exception( 206 | msg_or_exception.__class__, 207 | msg_or_exception, 208 | sys.exc_info()[2]) 209 | else: 210 | logger.info("Exiting: %s", msg_or_exception) 211 | 212 | if not mqtt_connection: 213 | logger.info("Disconnecting...") 214 | mqtt_connection.disconnect() 215 | sys.exit(0) 216 | 217 | 218 | def exit_handler(_signal, frame): 219 | """ 220 | Exit sample 221 | """ 222 | exit_sample(" Key abort") 223 | 224 | 225 | if __name__ == "__main__": 226 | signal.signal(signal.SIGINT, exit_handler) 227 | 228 | device_main() --------------------------------------------------------------------------------