├── docs ├── .nojekyll ├── objects.inv ├── _static │ ├── up.png │ ├── down.png │ ├── file.png │ ├── plus.png │ ├── comment.png │ ├── minus.png │ ├── ajax-loader.gif │ ├── down-pressed.png │ ├── up-pressed.png │ ├── comment-bright.png │ ├── comment-close.png │ ├── fonts │ │ ├── Lato │ │ │ ├── lato-bold.eot │ │ │ ├── lato-bold.ttf │ │ │ ├── lato-bold.woff │ │ │ ├── lato-bold.woff2 │ │ │ ├── lato-italic.eot │ │ │ ├── lato-italic.ttf │ │ │ ├── lato-italic.woff │ │ │ ├── lato-italic.woff2 │ │ │ ├── lato-regular.eot │ │ │ ├── lato-regular.ttf │ │ │ ├── lato-regular.woff │ │ │ ├── lato-bolditalic.eot │ │ │ ├── lato-bolditalic.ttf │ │ │ ├── lato-bolditalic.woff │ │ │ ├── lato-regular.woff2 │ │ │ └── lato-bolditalic.woff2 │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── fontawesome-webfont.woff2 │ │ └── RobotoSlab │ │ │ ├── roboto-slab-v7-bold.eot │ │ │ ├── roboto-slab-v7-bold.ttf │ │ │ ├── roboto-slab-v7-bold.woff │ │ │ ├── roboto-slab-v7-bold.woff2 │ │ │ ├── roboto-slab-v7-regular.eot │ │ │ ├── roboto-slab-v7-regular.ttf │ │ │ ├── roboto-slab-v7-regular.woff │ │ │ └── roboto-slab-v7-regular.woff2 │ ├── documentation_options.js │ ├── css │ │ └── badge_only.css │ ├── js │ │ └── theme.js │ └── pygments.css ├── _sources │ ├── _apidoc │ │ ├── modules.rst.txt │ │ ├── greengrasssdk.Lambda.rst.txt │ │ ├── greengrasssdk.client.rst.txt │ │ ├── greengrasssdk.IoTDataPlane.rst.txt │ │ ├── greengrasssdk.utils.testing.rst.txt │ │ ├── greengrasssdk.SecretsManager.rst.txt │ │ ├── greengrasssdk.stream_manager.util.rst.txt │ │ ├── greengrasssdk.stream_manager.data.rst.txt │ │ ├── greengrasssdk.stream_manager.exceptions.rst.txt │ │ ├── greengrasssdk.stream_manager.utilinternal.rst.txt │ │ ├── greengrasssdk.stream_manager.streammanagerclient.rst.txt │ │ ├── greengrasssdk.utils.rst.txt │ │ ├── greengrasssdk.rst.txt │ │ └── greengrasssdk.stream_manager.rst.txt │ └── index.rst.txt ├── .buildinfo ├── search.html ├── _apidoc │ ├── greengrasssdk.utils.html │ ├── greengrasssdk.client.html │ ├── greengrasssdk.utils.testing.html │ ├── modules.html │ ├── greengrasssdk.stream_manager.html │ ├── greengrasssdk.stream_manager.util.html │ └── greengrasssdk.html ├── _modules │ ├── index.html │ └── greengrasssdk │ │ ├── client.html │ │ ├── stream_manager │ │ └── util.html │ │ └── utils │ │ └── testing.html └── py-modindex.html ├── greengrasssdk ├── utils │ ├── __init__.py │ └── testing.py ├── __init__.py ├── client.py ├── stream_manager │ ├── __init__.py │ ├── util.py │ ├── exceptions.py │ └── utilinternal.py ├── IoTDataPlane.py ├── SecretsManager.py └── Lambda.py ├── requirements.txt ├── setup.cfg ├── MANIFEST.in ├── examples ├── BinaryLambdaInvoke │ ├── invokee.py │ └── invoker.py ├── Storyline_MessageLambda │ └── messageLambda.py ├── TES │ ├── lambda_function.py │ └── README ├── Storyline_UptimeLambda │ └── uptimeLambda.py ├── HelloWorldCounter │ └── greengrassHelloWorldCounter.py ├── HelloWorld │ └── greengrassHelloWorld.py ├── StreamManagerKinesis │ └── stream_manager_kinesis.py ├── StreamManagerIoTSiteWise │ └── stream_manager_ioT_siteWise.py ├── TrafficLight │ ├── carAggregator.py │ └── lightController.py └── StreamManagerS3 │ └── stream_manager_s3.py ├── CHANGELOG.rst ├── setup.py └── README.rst /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /greengrasssdk/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cbor2~=5.4.2 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt *.py 2 | recursive-include *.txt *.py -------------------------------------------------------------------------------- /docs/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/objects.inv -------------------------------------------------------------------------------- /docs/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/up.png -------------------------------------------------------------------------------- /docs/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/down.png -------------------------------------------------------------------------------- /docs/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/file.png -------------------------------------------------------------------------------- /docs/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/plus.png -------------------------------------------------------------------------------- /docs/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/comment.png -------------------------------------------------------------------------------- /docs/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/minus.png -------------------------------------------------------------------------------- /docs/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/comment-close.png -------------------------------------------------------------------------------- /docs/_sources/_apidoc/modules.rst.txt: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | greengrasssdk 8 | -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bold.eot -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bold.ttf -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bold.woff -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bold.woff2 -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-italic.eot -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-italic.ttf -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-italic.woff -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-italic.woff2 -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-regular.eot -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-regular.ttf -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-regular.woff -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bolditalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bolditalic.eot -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bolditalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bolditalic.ttf -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bolditalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bolditalic.woff -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-regular.woff2 -------------------------------------------------------------------------------- /docs/_static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/_static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/_static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/_static/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/_static/fonts/Lato/lato-bolditalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/Lato/lato-bolditalic.woff2 -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff -------------------------------------------------------------------------------- /docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-greengrass-core-sdk-python/HEAD/docs/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.Lambda.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.Lambda module 2 | =========================== 3 | 4 | .. automodule:: greengrasssdk.Lambda 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.client.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.client module 2 | =========================== 3 | 4 | .. automodule:: greengrasssdk.client 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.IoTDataPlane.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.IoTDataPlane module 2 | ================================= 3 | 4 | .. automodule:: greengrasssdk.IoTDataPlane 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.utils.testing.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.utils.testing module 2 | ================================== 3 | 4 | .. automodule:: greengrasssdk.utils.testing 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 03d99a6a6729b1944609d9a3797d89a8 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.SecretsManager.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.SecretsManager module 2 | =================================== 3 | 4 | .. automodule:: greengrasssdk.SecretsManager 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.stream_manager.util.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.stream\_manager.util module 2 | ========================================= 3 | 4 | .. automodule:: greengrasssdk.stream_manager.util 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.stream_manager.data.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.stream\_manager.data package 2 | ========================================== 3 | 4 | .. automodule:: greengrasssdk.stream_manager.data 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.stream_manager.exceptions.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.stream\_manager.exceptions module 2 | =============================================== 3 | 4 | .. automodule:: greengrasssdk.stream_manager.exceptions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.stream_manager.utilinternal.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.stream\_manager.utilinternal module 2 | ================================================= 3 | 4 | .. automodule:: greengrasssdk.stream_manager.utilinternal 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.stream_manager.streammanagerclient.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.stream\_manager.streammanagerclient module 2 | ======================================================== 3 | 4 | .. automodule:: greengrasssdk.stream_manager.streammanagerclient 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.utils.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.utils package 2 | =========================== 3 | 4 | .. automodule:: greengrasssdk.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | greengrasssdk.utils.testing 15 | 16 | -------------------------------------------------------------------------------- /docs/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | var DOCUMENTATION_OPTIONS = { 2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), 3 | VERSION: '1.6.1', 4 | LANGUAGE: 'None', 5 | COLLAPSE_INDEX: false, 6 | FILE_SUFFIX: '.html', 7 | HAS_SOURCE: true, 8 | SOURCELINK_SUFFIX: '.txt', 9 | NAVIGATION_WITH_KEYS: false, 10 | }; -------------------------------------------------------------------------------- /docs/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. include:: 2 | ../resources/README.rst 3 | 4 | API Documentation 5 | ================= 6 | * :doc:`IoTDataPlane <_apidoc/greengrasssdk.IoTDataPlane>` 7 | * :doc:`Lambda <_apidoc/greengrasssdk.Lambda>` 8 | * :doc:`SecretsManager <_apidoc/greengrasssdk.SecretsManager>` 9 | * :doc:`stream_manager <_apidoc/greengrasssdk.stream_manager>` 10 | * :ref:`genindex` 11 | -------------------------------------------------------------------------------- /examples/BinaryLambdaInvoke/invokee.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | import logging 5 | import sys 6 | 7 | # Setup logging to stdout 8 | logger = logging.getLogger(__name__) 9 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 10 | 11 | 12 | def handler(event, context): 13 | logger.info("Invoked with payload " + str(event)) 14 | return "Invoked successfully" 15 | -------------------------------------------------------------------------------- /greengrasssdk/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | from .client import client 6 | # .Lambda imports greengrass_common, which only applies within Greengrass Core. 7 | # Try-except as below to make sure the SDK is able to be imported outside of Greengrass Core 8 | try: 9 | from .Lambda import StreamingBody 10 | except: 11 | pass 12 | 13 | __version__ = '1.6.1' 14 | INTERFACE_VERSION = '1.5' 15 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk package 2 | ===================== 3 | 4 | .. automodule:: greengrasssdk 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | 14 | greengrasssdk.stream_manager 15 | greengrasssdk.utils 16 | 17 | Submodules 18 | ---------- 19 | 20 | .. toctree:: 21 | 22 | greengrasssdk.IoTDataPlane 23 | greengrasssdk.Lambda 24 | greengrasssdk.SecretsManager 25 | greengrasssdk.client 26 | 27 | -------------------------------------------------------------------------------- /docs/_sources/_apidoc/greengrasssdk.stream_manager.rst.txt: -------------------------------------------------------------------------------- 1 | greengrasssdk.stream\_manager package 2 | ===================================== 3 | 4 | .. automodule:: greengrasssdk.stream_manager 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | 14 | greengrasssdk.stream_manager.data 15 | 16 | Submodules 17 | ---------- 18 | 19 | .. toctree:: 20 | 21 | greengrasssdk.stream_manager.exceptions 22 | greengrasssdk.stream_manager.streammanagerclient 23 | greengrasssdk.stream_manager.util 24 | greengrasssdk.stream_manager.utilinternal 25 | 26 | -------------------------------------------------------------------------------- /greengrasssdk/client.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | 6 | def client(client_type, *args, **kwargs): 7 | if client_type == 'lambda': 8 | from .Lambda import Client 9 | elif client_type == 'iot-data': 10 | from .IoTDataPlane import Client 11 | elif client_type == 'secretsmanager': 12 | from .SecretsManager import Client 13 | elif client_type == 'streammanager': 14 | from .stream_manager import StreamManagerClient as Client 15 | else: 16 | raise Exception('Client type {} is not recognized.'.format(repr(client_type))) 17 | 18 | return Client(*args, **kwargs) 19 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | CHANGELOG 3 | ========= 4 | 5 | 1.6.1 6 | ===== 7 | Stream manager support for Python 3.10. 8 | 9 | 1.6.0 10 | ===== 11 | Stream manager supports automatic data export to AWS S3 and AWS IoT SiteWise, provides new API method to update existing streams, and pause or resume exporting. 12 | Support Python3.8 lambda runtime. 13 | 14 | 1.5.0 15 | ===== 16 | 17 | SDK supports StreamManager client. 18 | 19 | 1.4.0 20 | ====== 21 | 22 | Added support for Python 3.7 Lambda runtime. Lambda functions that use Python 3.7 can now run on an AWS IoT Greengrass core. (AWS IoT Greengrass continues to support Python 2.7 runtime.) 23 | 24 | 25 | 1.3.0 26 | ====== 27 | 28 | SDK supports SecretsManager client. 29 | 30 | 31 | 1.2.0 32 | ====== 33 | 34 | SDK and GGC compatibility check takes place in the background. 35 | 36 | 37 | 1.1.0 38 | ====== 39 | Lambda only accepted payload in JSON format. With this update, Invoking or publishing binary payload to a lambda is supported. 40 | -------------------------------------------------------------------------------- /examples/Storyline_MessageLambda/messageLambda.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | import logging 6 | import sys 7 | 8 | import greengrasssdk 9 | 10 | # Setup logging to stdout 11 | logger = logging.getLogger(__name__) 12 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 13 | 14 | client = greengrasssdk.client("iot-data") 15 | 16 | 17 | def message_handler(event, context): 18 | logger.info("Received message!") 19 | if "state" in event: 20 | if event["state"] == "on": 21 | client.update_thing_shadow(thingName="RobotArm_Thing", payload='{"state":{"desired":{"myState":"on"}}}') 22 | logger.info("Triggering publish to shadow " "topic to set state to ON") 23 | elif event["state"] == "off": 24 | client.update_thing_shadow(thingName="RobotArm_Thing", payload='{"state":{"desired":{"myState":"off"}}}') 25 | logger.info("Triggering publish to shadow " "topic to set state to OFF") 26 | -------------------------------------------------------------------------------- /greengrasssdk/stream_manager/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | """ 5 | 6 | # Export public facing objects 7 | # flake8: noqa 8 | 9 | from .streammanagerclient import StreamManagerClient, SDK_VERSION 10 | from .exceptions import * 11 | from .util import Util 12 | from .data import ( 13 | ReadMessagesOptions, 14 | MessageStreamDefinition, 15 | ExportDefinition, 16 | StrategyOnFull, 17 | Persistence, 18 | HTTPConfig, 19 | IoTAnalyticsConfig, 20 | KinesisConfig, 21 | ExportFormat, 22 | # Status related 23 | # Config 24 | StatusConfig, 25 | # Data 26 | StatusContext, 27 | StatusLevel, 28 | EventType, 29 | Status, 30 | StatusMessage, 31 | # S3 Tasks related: 32 | # Config 33 | S3ExportTaskExecutorConfig, 34 | # Data 35 | S3ExportTaskDefinition, 36 | # Iot SiteWise related: 37 | # Config 38 | IoTSiteWiseConfig, 39 | # Data 40 | Variant, 41 | Quality, 42 | TimeInNanos, 43 | AssetPropertyValue, 44 | PutAssetPropertyValueEntry, 45 | ) 46 | -------------------------------------------------------------------------------- /examples/TES/lambda_function.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | import logging 6 | import sys 7 | 8 | import greengrasssdk 9 | 10 | from botocore.session import Session 11 | 12 | # Setup logging to stdout 13 | logger = logging.getLogger(__name__) 14 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 15 | 16 | client = greengrasssdk.client("iot-data") 17 | 18 | logger.info("Hello from pinned lambda. Outside of handler.") 19 | 20 | # Get creds from TES 21 | # Note: must make sure that creds are not available within local folder 22 | # Can get cred info from /greengrass/var/log/system/tes.log 23 | session = Session() 24 | creds = session.get_credentials() 25 | formatted_creds = """ 26 | Access Key: {}\n 27 | Secret Key: {}\n 28 | Session Key: {}\n""".format( 29 | creds.access_key, creds.secret_key, creds.token 30 | ) 31 | 32 | # Logging credential information is not recommended. This is for demonstration purposes only. 33 | # logger.info(formatted_creds) 34 | 35 | 36 | def lambda_handler(event, context): 37 | logger.debug("Hello from pinned lambda. Inside handler.") 38 | return 39 | -------------------------------------------------------------------------------- /greengrasssdk/stream_manager/util.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | """ 5 | 6 | import json 7 | 8 | from .exceptions import ValidationException 9 | from .utilinternal import UtilInternal 10 | 11 | 12 | """ 13 | Util functions exposed to the customers 14 | """ 15 | 16 | 17 | class Util: 18 | """ 19 | Validate And Serialize an instance of class to Json bytes. 20 | :param data: an instance object 21 | :return: a byte array. 22 | :raises: :ValidationException 23 | """ 24 | 25 | @staticmethod 26 | def validate_and_serialize_to_json_bytes(data): 27 | validation = UtilInternal.is_invalid(data) 28 | if validation: 29 | raise ValidationException(validation) 30 | return UtilInternal.serialize_to_json_with_empty_array_as_null(data) 31 | 32 | """ 33 | Deserialize the json byte array to an object 34 | :param :bytes byte array of data 35 | :param :type instance class type 36 | :return: an object. 37 | """ 38 | 39 | @staticmethod 40 | def deserialize_json_bytes_to_obj(bytes, type): 41 | return type.from_dict(json.loads(bytes)) 42 | -------------------------------------------------------------------------------- /greengrasssdk/utils/testing.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | import json 6 | from functools import wraps 7 | from greengrass_common.env_vars import MY_FUNCTION_ARN 8 | 9 | 10 | def mock(func): 11 | """ 12 | mock decorates _invoke_internal by checking if MY_FUNCTION_ARN is present 13 | if MY_FUNCTION_ARN is present, the actual _invoke_internal is invoked 14 | otherwise, the mock _invoke_internal is invoked 15 | """ 16 | @wraps(func) 17 | def mock_invoke_internal(self, function_arn, payload, client_context, invocation_type="RequestResponse"): 18 | if MY_FUNCTION_ARN is None: 19 | if invocation_type == 'RequestResponse': 20 | return { 21 | 'Payload': json.dumps({ 22 | 'TestKey': 'TestValue' 23 | }), 24 | 'FunctionError': '' 25 | } 26 | elif invocation_type == 'Event': 27 | return { 28 | 'Payload': b'', 29 | 'FunctionError': '' 30 | } 31 | else: 32 | raise Exception('Unsupported invocation type {}'.format(invocation_type)) 33 | else: 34 | return func(self, function_arn, payload, client_context, invocation_type) 35 | return mock_invoke_internal 36 | -------------------------------------------------------------------------------- /examples/Storyline_UptimeLambda/uptimeLambda.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | import logging 6 | import sys 7 | 8 | import greengrasssdk 9 | 10 | # Setup logging to stdout 11 | logger = logging.getLogger(__name__) 12 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 13 | 14 | client = greengrasssdk.client("iot-data") 15 | 16 | 17 | def uptime_handler(event, context): 18 | logger.info("Received message!") 19 | if "state" in event: 20 | if event["state"] == "on": 21 | try: 22 | client.publish(topic="/topic/metering", queueFullPolicy="AllOrException", payload="Robot arm turned ON") 23 | logger.info("Triggering publish to topic " "/topic/metering with ON state") 24 | except Exception as e: 25 | logger.error("Failed to trigger publish to topic " "/topic/metering with ON state: " + repr(e)) 26 | elif event["state"] == "off": 27 | try: 28 | client.publish( 29 | topic="/topic/metering", queueFullPolicy="AllOrException", payload="Robot arm turned OFF" 30 | ) 31 | logger.info("Triggering publish to topic " "/topic/metering with OFF state") 32 | except Exception as e: 33 | logger.error("Failed to trigger publish to topic " "/topic/metering with OFF state: " + repr(e)) 34 | -------------------------------------------------------------------------------- /examples/BinaryLambdaInvoke/invoker.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | # This example demonstrates invoking a lambda with 'binary' encoding type. In 6 | # order to run this example, remember to mark your 'invokee' lambda as a binary 7 | # lambda. You can configure this on the lambda configuration page in the 8 | # console. After the lambdas get deployed to your Greengrass Core, you should 9 | # be able to see 'Invoked successfully' returned by 'invokee' lambda. A lambda 10 | # function can support non-json payload, which is a new feature introduced in 11 | # GGC version 1.5. 12 | 13 | import base64 14 | import json 15 | import logging 16 | import sys 17 | 18 | import greengrasssdk 19 | 20 | # Setup logging to stdout 21 | logger = logging.getLogger(__name__) 22 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 23 | 24 | client = greengrasssdk.client("lambda") 25 | 26 | 27 | def handler(event, context): 28 | client_context = json.dumps({"custom": "custom text"}) 29 | 30 | try: 31 | response = client.invoke( 32 | ClientContext=base64.b64encode(bytes(client_context)), 33 | FunctionName="arn:aws:lambda:::function::", 34 | InvocationType="RequestResponse", 35 | Payload="Non-JSON Data", 36 | Qualifier="1", 37 | ) 38 | 39 | logger.info(response["Payload"].read()) 40 | except Exception as e: 41 | logger.error(e) 42 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | distutils/setuptools install script. 5 | """ 6 | import os 7 | import re 8 | 9 | from setuptools import setup, find_packages 10 | 11 | 12 | ROOT = os.path.dirname(__file__) 13 | VERSION_RE = re.compile(r'''__version__ = ['"]([0-9.]+)['"]''') 14 | 15 | 16 | requires = [ 17 | "cbor2~=5.4.2" 18 | ] 19 | 20 | 21 | def get_version(): 22 | init = open(os.path.join(ROOT,'greengrasssdk','__init__.py')).read() 23 | version = VERSION_RE.search(init).group(1) 24 | if os.getenv("PYPI_TEST", False) == "True": 25 | import time 26 | return version + "." + str(int(time.time())) 27 | return version 28 | 29 | 30 | setup( 31 | name='greengrasssdk', 32 | version=get_version(), 33 | description='The AWS IoT Greengrass SDK for Python', 34 | long_description=open('README.rst').read(), 35 | author='Amazon Web Services', 36 | url='', 37 | scripts=[], 38 | packages=find_packages(), 39 | package_data={ 40 | 'greengrasssdk': [ 41 | ] 42 | }, 43 | include_package_data=True, 44 | install_requires=requires, 45 | license="Apache License 2.0", 46 | classifiers=[ 47 | 'Development Status :: 5 - Production/Stable', 48 | 'Intended Audience :: Developers', 49 | 'Natural Language :: English', 50 | 'License :: OSI Approved :: Apache Software License', 51 | 'Programming Language :: Python', 52 | 'Programming Language :: Python :: 2.7', 53 | 'Programming Language :: Python :: 3.7', 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /greengrasssdk/stream_manager/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | """ 5 | 6 | 7 | class StreamManagerException(Exception): 8 | def __init__(self, message="", status=None, request_id=None): 9 | super().__init__(message) 10 | self.status = status 11 | self.request_id = request_id 12 | self.message = message 13 | 14 | 15 | class ClientException(StreamManagerException): 16 | pass 17 | 18 | 19 | class ValidationException(ClientException): 20 | pass 21 | 22 | 23 | class ConnectFailedException(ClientException): 24 | pass 25 | 26 | 27 | class InvalidRequestException(StreamManagerException): 28 | pass 29 | 30 | 31 | class RequestPayloadTooLargeException(StreamManagerException): 32 | pass 33 | 34 | 35 | class ResourceNotFoundException(StreamManagerException): 36 | pass 37 | 38 | 39 | class ResponsePayloadTooLargeException(StreamManagerException): 40 | pass 41 | 42 | 43 | class ServerTimeoutException(StreamManagerException): 44 | pass 45 | 46 | 47 | class UnauthorizedException(StreamManagerException): 48 | pass 49 | 50 | 51 | class UnknownFailureException(StreamManagerException): 52 | pass 53 | 54 | 55 | class NotEnoughMessagesException(StreamManagerException): 56 | pass 57 | 58 | 59 | class MessageStoreReadErrorException(StreamManagerException): 60 | pass 61 | 62 | 63 | class ServerOutOfMemoryException(StreamManagerException): 64 | pass 65 | 66 | 67 | class UpdateFailedException(StreamManagerException): 68 | pass 69 | 70 | 71 | class UnknownOperationException(StreamManagerException): 72 | pass 73 | 74 | 75 | class UpdateNotAllowedException(InvalidRequestException): 76 | pass 77 | -------------------------------------------------------------------------------- /examples/HelloWorldCounter/greengrassHelloWorldCounter.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | # greengrassHelloWorldCounter.py 6 | # Demonstrates a simple publish to a topic using Greengrass core sdk 7 | # This lambda function will retrieve underlying platform information and send a hello world message along with the 8 | # platform information to the topic 'hello/world/counter' along with a counter to keep track of invocations. 9 | # 10 | # This Lambda function requires the AWS Greengrass SDK to run on Greengrass devices. 11 | # This can be found on the AWS IoT Console. 12 | 13 | import json 14 | import logging 15 | import platform 16 | import sys 17 | import time 18 | 19 | import greengrasssdk 20 | 21 | # Setup logging to stdout 22 | logger = logging.getLogger(__name__) 23 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 24 | 25 | # Creating a greengrass core sdk client 26 | client = greengrasssdk.client("iot-data") 27 | 28 | # Retrieving platform information to send from Greengrass Core 29 | my_platform = platform.platform() 30 | 31 | # Counter to keep track of invocations of the function_handler 32 | my_counter = 0 33 | 34 | 35 | def function_handler(event, context): 36 | global my_counter 37 | my_counter = my_counter + 1 38 | try: 39 | if not my_platform: 40 | client.publish( 41 | topic="hello/world/counter", 42 | queueFullPolicy="AllOrException", 43 | payload=json.dumps( 44 | {"message": "Hello world! Sent from Greengrass Core. Invocation Count: {}".format(my_counter)} 45 | ), 46 | ) 47 | else: 48 | client.publish( 49 | topic="hello/world/counter", 50 | queueFullPolicy="AllOrException", 51 | payload=json.dumps( 52 | { 53 | "message": "Hello world! Sent from Greengrass Core running on platform: {}.".format(my_platform) 54 | + " Invocation Count: {}".format(my_counter) 55 | } 56 | ), 57 | ) 58 | except Exception as e: 59 | logger.error("Failed to publish message: " + repr(e)) 60 | time.sleep(20) 61 | return 62 | -------------------------------------------------------------------------------- /examples/HelloWorld/greengrassHelloWorld.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | # greengrassHelloWorld.py 6 | # Demonstrates a simple publish to a topic using Greengrass core sdk 7 | # This lambda function will retrieve underlying platform information and send 8 | # a hello world message along with the platform information to the topic 9 | # 'hello/world'. The function will sleep for five seconds, then repeat. 10 | # Since the function is long-lived it will run forever when deployed to a 11 | # Greengrass core. The handler will NOT be invoked in our example since 12 | # the we are executing an infinite loop. 13 | 14 | import logging 15 | import platform 16 | import sys 17 | from threading import Timer 18 | 19 | import greengrasssdk 20 | 21 | # Setup logging to stdout 22 | logger = logging.getLogger(__name__) 23 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 24 | 25 | # Creating a greengrass core sdk client 26 | client = greengrasssdk.client("iot-data") 27 | 28 | # Retrieving platform information to send from Greengrass Core 29 | my_platform = platform.platform() 30 | 31 | 32 | # When deployed to a Greengrass core, this code will be executed immediately 33 | # as a long-lived lambda function. The code will enter the infinite while 34 | # loop below. 35 | # If you execute a 'test' on the Lambda Console, this test will fail by 36 | # hitting the execution timeout of three seconds. This is expected as 37 | # this function never returns a result. 38 | 39 | 40 | def greengrass_hello_world_run(): 41 | try: 42 | if not my_platform: 43 | client.publish( 44 | topic="hello/world", queueFullPolicy="AllOrException", payload="Hello world! Sent from Greengrass Core." 45 | ) 46 | else: 47 | client.publish( 48 | topic="hello/world", 49 | queueFullPolicy="AllOrException", 50 | payload="Hello world! Sent from " "Greengrass Core running on platform: {}".format(my_platform), 51 | ) 52 | except Exception as e: 53 | logger.error("Failed to publish message: " + repr(e)) 54 | 55 | # Asynchronously schedule this function to be run again in 5 seconds 56 | Timer(5, greengrass_hello_world_run).start() 57 | 58 | 59 | # Start executing the function above 60 | greengrass_hello_world_run() 61 | 62 | 63 | # This is a dummy handler and will not be invoked 64 | # Instead the code above will be executed in an infinite loop for our example 65 | def function_handler(event, context): 66 | return 67 | -------------------------------------------------------------------------------- /examples/TES/README: -------------------------------------------------------------------------------- 1 | The TES example package contains a Lambda function that, when run, 2 | will attempt to retrieve AWS credentials. The goal of TES is to allow 3 | users to retrieve credentials without having them hard-coded on the 4 | system itself. 5 | 6 | Assuming no credentials exist on the system, when the Lambda function 7 | is run, temporary credentials will be sourced from the cloud. They 8 | will be formatted as . 9 | 10 | The code sample performs logger initialization and credential retrieval 11 | is outside of the function handler. This means that a pinned lambda 12 | should be used to test functionality. 13 | 14 | In case you would like to use an On-Demand Lambda function, you will then 15 | need to create a subscription to invoke the Lambda function 16 | (so that the handler is executed). 17 | 18 | ### SETUP ### 19 | 1. In order to use this example, you will need to include greengrasssdk, boto3, 20 | botocore and any of the dependencies those libraries require in the zip file before 21 | uploading it. 22 | 23 | 2. After creating a zip file, create a Lambda function 24 | in the Lambda Console. 25 | 26 | Handler: lambda_function.lambda_handler 27 | Runtime: python2.7 28 | Timeout: 3s 29 | Role: any basic execution role can be used here 30 | 31 | 3. Create a group that contains your Greengrass Core and the Lambda 32 | function you've just created. 33 | 34 | 4. Deploy the latest Greengrass release to your device. 35 | 36 | 5. Ensure that your logging configuration includes either a logging 37 | configuration for CW, the FileSystem, or both. For example: 38 | 39 | "Logging": { 40 | "Content": [ 41 | { 42 | "Type": "FileSystem", 43 | "Component": "GreengrassSystem", 44 | "Level": "DEBUG", 45 | "Space": 25600 46 | }, 47 | { 48 | "Type": "FileSystem", 49 | "Component": "Lambda", 50 | "Level": "DEBUG", 51 | "Space": 25600 52 | }, 53 | { 54 | "Type": "AWSCloudWatch", 55 | "Component": "Lambda", 56 | "Level": "DEBUG" 57 | }, 58 | { 59 | "Type": "AWSCloudWatch", 60 | "Component": "GreengrassSystem", 61 | "Level": "DEBUG" 62 | } 63 | ] 64 | } 65 | 66 | 6. Make a deployment to your Greengrass Core, then start your Greengrass 67 | Core. The core will check for any new deployments and will proceed to 68 | download the newest configuration file (group.json) as well as the Lambda 69 | function you've created. 70 | 71 | 7. Check either the local logs or CloudWatch logs for output from the function. 72 | 73 | Local Path: /greengrass/var/log/user///.log 74 | CloudWatch: /aws/greengrass/Lambda/// 75 | -------------------------------------------------------------------------------- /docs/_static/css/badge_only.css: -------------------------------------------------------------------------------- 1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} 2 | -------------------------------------------------------------------------------- /examples/StreamManagerKinesis/stream_manager_kinesis.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import random 4 | import time 5 | 6 | from greengrasssdk.stream_manager import ( 7 | ExportDefinition, 8 | KinesisConfig, 9 | MessageStreamDefinition, 10 | ReadMessagesOptions, 11 | ResourceNotFoundException, 12 | StrategyOnFull, 13 | StreamManagerClient, 14 | ) 15 | 16 | # This example will create a Greengrass StreamManager stream called "SomeStream". 17 | # It will then start writing data into that stream and StreamManager will 18 | # automatically export the written data to a Kinesis Data Stream called "MyKinesisStream". 19 | # This example will run forever, until the program is killed. 20 | 21 | # The size of the StreamManager stream on disk will not exceed the default (which is 256 MB). 22 | # Any data appended after the stream reaches the size limit, will continue to be appended, and 23 | # StreamManager will delete the oldest data until the total stream size is back under 256MB. 24 | # The Kinesis Data Stream in the cloud has no such bound, so all the data from this script 25 | # will be uploaded to Kinesis and you will be charged for that usage. 26 | 27 | 28 | def main(logger): 29 | try: 30 | stream_name = "SomeStream" 31 | kinesis_stream_name = "MyKinesisStream" 32 | 33 | # Create a client for the StreamManager 34 | client = StreamManagerClient() 35 | 36 | # Try deleting the stream (if it exists) so that we have a fresh start 37 | try: 38 | client.delete_message_stream(stream_name=stream_name) 39 | except ResourceNotFoundException: 40 | pass 41 | 42 | exports = ExportDefinition( 43 | kinesis=[KinesisConfig(identifier="KinesisExport" + stream_name, kinesis_stream_name=kinesis_stream_name)] 44 | ) 45 | client.create_message_stream( 46 | MessageStreamDefinition( 47 | name=stream_name, strategy_on_full=StrategyOnFull.OverwriteOldestData, export_definition=exports 48 | ) 49 | ) 50 | 51 | # Append 2 messages and print their sequence numbers 52 | logger.info( 53 | "Successfully appended message to stream with sequence number %d", 54 | client.append_message(stream_name, "ABCDEFGHIJKLMNO".encode("utf-8")), 55 | ) 56 | logger.info( 57 | "Successfully appended message to stream with sequence number %d", 58 | client.append_message(stream_name, "PQRSTUVWXYZ".encode("utf-8")), 59 | ) 60 | 61 | # Try reading the 2 messages we just appended and print them out 62 | logger.info( 63 | "Successfully read 2 messages: %s", 64 | client.read_messages(stream_name, ReadMessagesOptions(min_message_count=2, read_timeout_millis=1000)), 65 | ) 66 | 67 | logger.info("Now going to start writing random integers between 0 and 1000 to the stream") 68 | # Now start putting in random data between 0 and 1000 to emulate device sensor input 69 | while True: 70 | logger.debug("Appending new random integer to stream") 71 | client.append_message(stream_name, random.randint(0, 1000).to_bytes(length=4, signed=True, byteorder="big")) 72 | time.sleep(1) 73 | 74 | except asyncio.TimeoutError: 75 | logger.exception("Timed out while executing") 76 | except Exception: 77 | logger.exception("Exception while running") 78 | finally: 79 | # Always close the client to avoid resource leaks 80 | if client: 81 | client.close() 82 | 83 | 84 | def function_handler(event, context): 85 | return 86 | 87 | 88 | logging.basicConfig(level=logging.INFO) 89 | # Start up this sample code 90 | main(logger=logging.getLogger()) 91 | -------------------------------------------------------------------------------- /examples/StreamManagerIoTSiteWise/stream_manager_ioT_siteWise.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import calendar 3 | import logging 4 | import random 5 | import time 6 | import uuid 7 | 8 | from greengrasssdk.stream_manager import ( 9 | AssetPropertyValue, 10 | ExportDefinition, 11 | IoTSiteWiseConfig, 12 | MessageStreamDefinition, 13 | PutAssetPropertyValueEntry, 14 | Quality, 15 | ResourceNotFoundException, 16 | StrategyOnFull, 17 | StreamManagerClient, 18 | TimeInNanos, 19 | Variant, 20 | ) 21 | from greengrasssdk.stream_manager.util import Util 22 | 23 | # This example will create a Greengrass StreamManager stream called "SomeStream". 24 | # It will then start writing data into that stream and StreamManager will 25 | # automatically export the written data to the customer-created property alias. 26 | # This example will run forever, until the program is killed. 27 | 28 | # The size of the StreamManager stream on disk will not exceed the default (which is 256 MB). 29 | # Any data appended after the stream reaches the size limit, will continue to be appended, and 30 | # StreamManager will delete the oldest data until the total stream size is back under 256MB. 31 | 32 | 33 | property_alias = "SomePropertyAlias" 34 | 35 | 36 | # This will create a random asset property value entry and return it to the caller. 37 | def get_random_site_wise_entry(): 38 | 39 | # SiteWise requires unique timestamps in all messages and also needs timstamps not earlier 40 | # than 10 minutes in the past. Add some randomness to time and offset. 41 | 42 | # Note: Inorder to create a new asset property data, you should use the classes defined in the 43 | # greengrasssdk.stream_manager module. 44 | 45 | time_in_nanos = TimeInNanos( 46 | time_in_seconds=calendar.timegm(time.gmtime()) - random.randint(0, 60), offset_in_nanos=random.randint(0, 10000) 47 | ) 48 | variant = Variant(double_value=random.random()) 49 | asset = [AssetPropertyValue(value=variant, quality=Quality.GOOD, timestamp=time_in_nanos)] 50 | return PutAssetPropertyValueEntry(entry_id=str(uuid.uuid4()), property_alias=property_alias, property_values=asset) 51 | 52 | 53 | def main(logger): 54 | try: 55 | stream_name = "SomeStream" 56 | client = StreamManagerClient() 57 | 58 | # Try deleting the stream (if it exists) so that we have a fresh start 59 | try: 60 | client.delete_message_stream(stream_name=stream_name) 61 | except ResourceNotFoundException: 62 | pass 63 | 64 | exports = ExportDefinition( 65 | iot_sitewise=[IoTSiteWiseConfig(identifier="IoTSiteWiseExport" + stream_name, batch_size=5)] 66 | ) 67 | client.create_message_stream( 68 | MessageStreamDefinition( 69 | name=stream_name, strategy_on_full=StrategyOnFull.OverwriteOldestData, export_definition=exports 70 | ) 71 | ) 72 | 73 | logger.info("Now going to start writing random IoTSiteWiseEntry to the stream") 74 | # Now start putting in random site wise entries. 75 | while True: 76 | logger.debug("Appending new random IoTSiteWiseEntry to stream") 77 | client.append_message(stream_name, Util.validate_and_serialize_to_json_bytes(get_random_site_wise_entry())) 78 | time.sleep(1) 79 | except asyncio.TimeoutError: 80 | print("Timed out") 81 | except Exception as e: 82 | print(e) 83 | print(type(e)) 84 | finally: 85 | if client: 86 | client.close() 87 | 88 | 89 | logging.basicConfig(level=logging.INFO) 90 | # Start up this sample code 91 | main(logger=logging.getLogger()) 92 | 93 | 94 | # This is a dummy handler and will not be invoked 95 | # Instead the code above will be executed in an infinite loop for our example 96 | def function_handler(event, context): 97 | return 98 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Greengrass Core Python SDK 2 | ========================== 3 | 4 | The AWS IoT Greengrass Core SDK is meant to be used by AWS Lambda functions running on an AWS IoT Greengrass Core. It will enable Lambda functions to invoke other Lambda functions deployed to the Greengrass Core, publish messages to the Greengrass Core and work with the local Shadow service. 5 | 6 | ================================= 7 | Using AWS IoT Greengrass Core SDK 8 | ================================= 9 | 10 | To use the AWS IoT Greengrass Core SDK, you must first import the AWS IoT Greengrass Core SDK in your Lambda function as you would with any other external libraries. You then need to create a client for 'iot-data' or 'lambda'. Use 'iot-data' if you wish to publish messages to the local Greengrass Core and interact with the local Shadow service. Use 'lambda' if you wish to invoke other Lambda functions deployed to the same Greengrass Core. 11 | 12 | Here is an example for using the 'iot-data' client 13 | 14 | .. code-block:: python 15 | 16 | import greengrasssdk 17 | 18 | # Let's instantiate the iot-data client 19 | client = greengrasssdk.client('iot-data') 20 | 21 | 22 | Now that you have an ``iot-data`` client, you can publish requests. 23 | 24 | .. code-block:: python 25 | 26 | response = client.publish( 27 | topic='someTopic', 28 | payload='some data'.encode() 29 | ) 30 | 31 | Here is an example for using the 'lambda' client. 32 | 33 | .. code-block:: python 34 | 35 | import greengrasssdk 36 | 37 | client = greengrasssdk.client('lambda') 38 | 39 | Now that you have a lambda client, you can publish requests. 40 | 41 | .. code-block:: python 42 | 43 | # Define the payload to pass to the invoked lambda function 44 | msg = json.dumps({ 45 | 'message':"hello" 46 | }) 47 | 48 | # Invoke the lambda function 49 | response = client.invoke( 50 | FunctionName='arn::lambda:::function:', 51 | InvocationType='RequestResponse', 52 | Payload=payload, 53 | Qualifier='2' 54 | ) 55 | 56 | ============== 57 | Compatibility 58 | ============== 59 | 60 | As new features are added to AWS IoT Greengrass, newer versions of the AWS IoT Greengrass SDK may be incompatible with older versions of the AWS IoT Greengrass core. The following table lists the compatible SDKs for all GGC releases. 61 | 62 | +-------------+------------------------+ 63 | | GGC Version | Compatible SDK Versions| 64 | +=============+========================+ 65 | | 1.0.x-1.6.x | 1.0.x-1.2.x | 66 | +-------------+------------------------+ 67 | | 1.7.x-1.8.x | 1.0.x-1.3.x | 68 | +-------------+------------------------+ 69 | | 1.9.x | 1.0.x-1.4.x | 70 | +-------------+------------------------+ 71 | | 1.10.x | 1.0.x-1.5.x | 72 | +-------------+------------------------+ 73 | | 1.11.x | 1.0.x-1.6.x | 74 | +-------------+------------------------+ 75 | 76 | ============== 77 | Stream Manager 78 | ============== 79 | 80 | Greengrass version 1.10 comes with a new optional feature, Stream Manager. This SDK supports Stream Manager, but it has additional requirements. Specifically, Stream Manager requires Python version 3.7 or above. It also has package requirements listed in the requirements.txt file. Please install these requirements and bundle it with your lambda zip package. 81 | 82 | To install the requirements you can use pip such as :code:`pip install --target . -r requirements.txt`. This will install the requirements to the directory that you run the command in. In order to work in Greengrass the dependencies must be bundled in the zip with your lambda code. 83 | With the pip command above, the dependencies will be installed to the current directory. The dependencies must be bundled with your lambda code, so if the current directory doesn't have your 84 | lambda code, then simply copy the installed dependencies to the directory which contains your code. 85 | -------------------------------------------------------------------------------- /docs/_static/js/theme.js: -------------------------------------------------------------------------------- 1 | /* sphinx_rtd_theme version 0.4.0 | MIT license */ 2 | /* Built 20180606 11:06 */ 3 | require=function n(e,i,t){function o(s,a){if(!i[s]){if(!e[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var u=i[s]={exports:{}};e[s][0].call(u.exports,function(n){var i=e[s][1][n];return o(i||n)},u,u.exports,n,e,i,t)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var i=n(this);expand=n(''),expand.on("click",function(n){return e.toggleCurrent(i),n.stopPropagation(),!1}),i.prepend(expand)})},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),i=e.find('[href="'+n+'"]');if(0===i.length){var t=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(i=e.find('[href="#'+t.attr("id")+'"]')).length&&(i=e.find('[href="#"]'))}i.length>0&&($(".wy-menu-vertical .current").removeClass("current"),i.addClass("current"),i.closest("li.toctree-l1").addClass("current"),i.closest("li.toctree-l1").parent().addClass("current"),i.closest("li.toctree-l1").addClass("current"),i.closest("li.toctree-l2").addClass("current"),i.closest("li.toctree-l3").addClass("current"),i.closest("li.toctree-l4").addClass("current"))}catch(o){console.log("Error expanding nav for anchor",o)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,i=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(i),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:e.exports.ThemeNav,StickyNav:e.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],i=0;i } } } 90 | logger.info(event) 91 | lightValue = event["current"]["state"]["reported"]["property"] 92 | logger.info("reported light state: " + lightValue) 93 | if lightValue == "G": 94 | logger.info("Green light") 95 | 96 | # generate a random number of cars passing during this green light 97 | cars = randint(1, 20) 98 | 99 | # update stats 100 | totalTraffic += cars 101 | totalGreenlights += 1 102 | if cars < minCars or minCars == -1: 103 | minCars = cars 104 | if cars > maxCars: 105 | maxCars = cars 106 | 107 | logger.info("Cars passed during green light: " + str(cars)) 108 | logger.info("Total Traffic: " + str(totalTraffic)) 109 | logger.info("Total Greenlights: " + str(totalGreenlights)) 110 | logger.info("Minimum Cars passing: " + str(minCars)) 111 | logger.info("Maximum Cars passing: " + str(maxCars)) 112 | 113 | # update car stats to dynamodb every 3 green lights 114 | if totalGreenlights % 3 == 0: 115 | global tableName 116 | table = dynamodb.Table(tableName) 117 | table.put_item( 118 | Item={ 119 | "Time": str(datetime.utcnow()), 120 | "TotalTraffic": totalTraffic, 121 | "TotalGreenlights": totalGreenlights, 122 | "MinCarsPassing": minCars, 123 | "MaxCarsPassing": maxCars, 124 | } 125 | ) 126 | return 127 | -------------------------------------------------------------------------------- /docs/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Search — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 90 | 91 |
92 | 93 | 94 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
123 | 124 |
    125 | 126 |
  • Docs »
  • 127 | 128 |
  • Search
  • 129 | 130 | 131 |
  • 132 | 133 | 134 | 135 |
  • 136 | 137 |
138 | 139 | 140 |
141 |
142 |
143 |
144 | 145 | 153 | 154 | 155 |
156 | 157 |
158 | 159 |
160 | 161 |
162 |
163 | 164 | 165 |
166 | 167 |
168 |

169 | © Copyright 2022, Amazon.com. 170 | 171 |

172 |
173 | Built with Sphinx using a theme provided by Read the Docs. 174 | 175 |
176 | 177 |
178 |
179 | 180 |
181 | 182 |
183 | 184 | 185 | 186 | 187 | 188 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 214 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /docs/_apidoc/greengrasssdk.utils.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.utils package — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 96 | 97 |
98 | 99 | 100 | 106 | 107 | 108 |
109 | 110 |
111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 |
129 | 130 |
    131 | 132 |
  • Docs »
  • 133 | 134 |
  • greengrasssdk.utils package
  • 135 | 136 | 137 |
  • 138 | 139 | 140 | View page source 141 | 142 | 143 |
  • 144 | 145 |
146 | 147 | 148 |
149 |
150 |
151 |
152 | 153 |
154 |

greengrasssdk.utils package

155 |
156 |

Submodules

157 |
158 | 161 |
162 |
163 |
164 | 165 | 166 |
167 | 168 |
169 |
170 | 171 | 172 |
173 | 174 |
175 |

176 | © Copyright 2022, Amazon.com. 177 | 178 |

179 |
180 | Built with Sphinx using a theme provided by Read the Docs. 181 | 182 |
183 | 184 |
185 |
186 | 187 |
188 | 189 |
190 | 191 | 192 | 193 | 194 | 195 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /docs/_modules/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Overview: module code — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 90 | 91 |
92 | 93 | 94 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
123 | 124 |
    125 | 126 |
  • Docs »
  • 127 | 128 |
  • Overview: module code
  • 129 | 130 | 131 |
  • 132 | 133 |
  • 134 | 135 |
136 | 137 | 138 |
139 |
140 | 159 |
160 | 161 | 162 |
163 | 164 |
165 |

166 | © Copyright 2022, Amazon.com. 167 | 168 |

169 |
170 | Built with Sphinx using a theme provided by Read the Docs. 171 | 172 |
173 | 174 |
175 |
176 | 177 |
178 | 179 |
180 | 181 | 182 | 183 | 184 | 185 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /docs/_apidoc/greengrasssdk.client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.client module — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 93 | 94 |
95 | 96 | 97 | 103 | 104 | 105 |
106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 |
    128 | 129 |
  • Docs »
  • 130 | 131 |
  • greengrasssdk.client module
  • 132 | 133 | 134 |
  • 135 | 136 | 137 | View page source 138 | 139 | 140 |
  • 141 | 142 |
143 | 144 | 145 |
146 |
147 |
148 |
149 | 150 |
151 |

greengrasssdk.client module

152 |
153 |
154 | greengrasssdk.client.client(client_type, *args, **kwargs)[source]
155 |
156 | 157 |
158 | 159 | 160 |
161 | 162 |
163 |
164 | 165 | 166 |
167 | 168 |
169 |

170 | © Copyright 2022, Amazon.com. 171 | 172 |

173 |
174 | Built with Sphinx using a theme provided by Read the Docs. 175 | 176 |
177 | 178 |
179 |
180 | 181 |
182 | 183 |
184 | 185 | 186 | 187 | 188 | 189 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /examples/StreamManagerS3/stream_manager_s3.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import time 4 | 5 | from greengrasssdk.stream_manager import ( 6 | ExportDefinition, 7 | MessageStreamDefinition, 8 | ReadMessagesOptions, 9 | ResourceNotFoundException, 10 | S3ExportTaskDefinition, 11 | S3ExportTaskExecutorConfig, 12 | Status, 13 | StatusConfig, 14 | StatusLevel, 15 | StatusMessage, 16 | StrategyOnFull, 17 | StreamManagerClient, 18 | StreamManagerException, 19 | ) 20 | from greengrasssdk.stream_manager.util import Util 21 | 22 | # This example creates a local stream named "SomeStream", and a status stream named "SomeStatusStream. 23 | # It adds 1 S3 Export task into the "SomeStream" stream and then stream manager automatically exports 24 | # the data to a customer-created S3 bucket named "SomeBucket". 25 | # This example runs until the customer-created file at URL "SomeURL" has been uploaded to the S3 bucket. 26 | 27 | 28 | def main(logger): 29 | try: 30 | stream_name = "SomeStream" 31 | status_stream_name = "SomeStatusStreamName" 32 | bucket_name = "SomeBucket" 33 | key_name = "SomeKey" 34 | file_url = "file:/path/to/some/file.someExtension" 35 | client = StreamManagerClient() 36 | 37 | # Try deleting the status stream (if it exists) so that we have a fresh start 38 | try: 39 | client.delete_message_stream(stream_name=status_stream_name) 40 | except ResourceNotFoundException: 41 | pass 42 | 43 | # Try deleting the stream (if it exists) so that we have a fresh start 44 | try: 45 | client.delete_message_stream(stream_name=stream_name) 46 | except ResourceNotFoundException: 47 | pass 48 | 49 | exports = ExportDefinition( 50 | s3_task_executor=[ 51 | S3ExportTaskExecutorConfig( 52 | identifier="S3TaskExecutor" + stream_name, # Required 53 | # Optional. Add an export status stream to add statuses for all S3 upload tasks. 54 | status_config=StatusConfig( 55 | status_level=StatusLevel.INFO, # Default is INFO level statuses. 56 | # Status Stream should be created before specifying in S3 Export Config. 57 | status_stream_name=status_stream_name, 58 | ), 59 | ) 60 | ] 61 | ) 62 | 63 | # Create the Status Stream. 64 | client.create_message_stream( 65 | MessageStreamDefinition(name=status_stream_name, strategy_on_full=StrategyOnFull.OverwriteOldestData) 66 | ) 67 | 68 | # Create the message stream with the S3 Export definition. 69 | client.create_message_stream( 70 | MessageStreamDefinition( 71 | name=stream_name, strategy_on_full=StrategyOnFull.OverwriteOldestData, export_definition=exports 72 | ) 73 | ) 74 | 75 | # Append a S3 Task definition and print the sequence number 76 | s3_export_task_definition = S3ExportTaskDefinition(input_url=file_url, bucket=bucket_name, key=key_name) 77 | logger.info( 78 | "Successfully appended S3 Task Definition to stream with sequence number %d", 79 | client.append_message(stream_name, Util.validate_and_serialize_to_json_bytes(s3_export_task_definition)), 80 | ) 81 | 82 | # Read the statuses from the export status stream 83 | stop_checking = False 84 | next_seq = 0 85 | while not stop_checking: 86 | try: 87 | messages_list = client.read_messages( 88 | status_stream_name, 89 | ReadMessagesOptions( 90 | desired_start_sequence_number=next_seq, min_message_count=1, read_timeout_millis=1000 91 | ), 92 | ) 93 | for message in messages_list: 94 | # Deserialize the status message first. 95 | status_message = Util.deserialize_json_bytes_to_obj(message.payload, StatusMessage) 96 | 97 | # Check the status of the status message. If the status is "Success", 98 | # the file was successfully uploaded to S3. 99 | # If the status was either "Failure" or "Cancelled", the server was unable to upload the file to S3. 100 | # We will print the message for why the upload to S3 failed from the status message. 101 | # If the status was "InProgress", the status indicates that the server has started uploading 102 | # the S3 task. 103 | if status_message.status == Status.Success: 104 | logger.info("Successfully uploaded file at path " + file_url + " to S3.") 105 | stop_checking = True 106 | elif status_message.status == Status.InProgress: 107 | logger.info("File upload is in Progress.") 108 | next_seq = message.sequence_number + 1 109 | elif status_message.status == Status.Failure or status_message.status == Status.Canceled: 110 | logger.info( 111 | "Unable to upload file at path " + file_url + " to S3. Message: " + status_message.message 112 | ) 113 | stop_checking = True 114 | if not stop_checking: 115 | time.sleep(5) 116 | except StreamManagerException: 117 | logger.exception("Exception while running") 118 | time.sleep(5) 119 | except asyncio.TimeoutError: 120 | logger.exception("Timed out while executing") 121 | except Exception: 122 | logger.exception("Exception while running") 123 | finally: 124 | if client: 125 | client.close() 126 | 127 | 128 | logging.basicConfig(level=logging.INFO) 129 | # Start up this sample code 130 | main(logger=logging.getLogger()) 131 | 132 | 133 | # This is a dummy handler and will not be invoked 134 | # Instead the code above will be executed in an infinite loop for our example 135 | def function_handler(event, context): 136 | return 137 | -------------------------------------------------------------------------------- /docs/_apidoc/greengrasssdk.utils.testing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.utils.testing module — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 93 | 94 |
95 | 96 | 97 | 103 | 104 | 105 |
106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 |
    128 | 129 |
  • Docs »
  • 130 | 131 |
  • greengrasssdk.utils.testing module
  • 132 | 133 | 134 |
  • 135 | 136 | 137 | View page source 138 | 139 | 140 |
  • 141 | 142 |
143 | 144 | 145 |
146 |
147 |
148 |
149 | 150 |
151 |

greengrasssdk.utils.testing module

152 |
153 |
154 | greengrasssdk.utils.testing.mock(func)[source]
155 |

mock decorates _invoke_internal by checking if MY_FUNCTION_ARN is present 156 | if MY_FUNCTION_ARN is present, the actual _invoke_internal is invoked 157 | otherwise, the mock _invoke_internal is invoked

158 |
159 | 160 |
161 | 162 | 163 |
164 | 165 |
166 |
167 | 168 | 169 |
170 | 171 |
172 |

173 | © Copyright 2022, Amazon.com. 174 | 175 |

176 |
177 | Built with Sphinx using a theme provided by Read the Docs. 178 | 179 |
180 | 181 |
182 |
183 | 184 |
185 | 186 |
187 | 188 | 189 | 190 | 191 | 192 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /greengrasssdk/IoTDataPlane.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | import base64 6 | import json 7 | import logging 8 | 9 | from greengrasssdk import Lambda 10 | from greengrass_common.env_vars import SHADOW_FUNCTION_ARN, ROUTER_FUNCTION_ARN, MY_FUNCTION_ARN 11 | 12 | # Log messages in the SDK are part of customer's log because they're helpful for debugging 13 | # customer's lambdas. Since we configured the root logger to log to customer's log and set the 14 | # propagate flag of this logger to True. The log messages submitted from this logger will be 15 | # sent to the customer's local Cloudwatch handler. 16 | customer_logger = logging.getLogger(__name__) 17 | customer_logger.propagate = True 18 | 19 | 20 | class ShadowError(Exception): 21 | pass 22 | 23 | 24 | class Client: 25 | def __init__(self): 26 | self.lambda_client = Lambda.Client() 27 | 28 | def get_thing_shadow(self, **kwargs): 29 | r""" 30 | Call shadow lambda to obtain current shadow state. 31 | 32 | :Keyword Arguments: 33 | * *thingName* (``string``) -- 34 | [REQUIRED] 35 | The name of the thing. 36 | 37 | :returns: (``dict``) -- 38 | The output from the GetThingShadow operation 39 | * *payload* (``bytes``) -- 40 | The state information, in JSON format. 41 | """ 42 | thing_name = self._get_required_parameter('thingName', **kwargs) 43 | payload = b'' 44 | 45 | return self._shadow_op('get', thing_name, payload) 46 | 47 | def update_thing_shadow(self, **kwargs): 48 | r""" 49 | Updates the thing shadow for the specified thing. 50 | 51 | :Keyword Arguments: 52 | * *thingName* (``string``) -- 53 | [REQUIRED] 54 | The name of the thing. 55 | * *payload* (``bytes or seekable file-like object``) -- 56 | [REQUIRED] 57 | The state information, in JSON format. 58 | 59 | :returns: (``dict``) -- 60 | The output from the UpdateThingShadow operation 61 | * *payload* (``bytes``) -- 62 | The state information, in JSON format. 63 | """ 64 | thing_name = self._get_required_parameter('thingName', **kwargs) 65 | payload = self._get_required_parameter('payload', **kwargs) 66 | 67 | return self._shadow_op('update', thing_name, payload) 68 | 69 | def delete_thing_shadow(self, **kwargs): 70 | r""" 71 | Deletes the thing shadow for the specified thing. 72 | 73 | :Keyword Arguments: 74 | * *thingName* (``string``) -- 75 | [REQUIRED] 76 | The name of the thing. 77 | 78 | :returns: (``dict``) -- 79 | The output from the DeleteThingShadow operation 80 | * *payload* (``bytes``) -- 81 | The state information, in JSON format. 82 | """ 83 | thing_name = self._get_required_parameter('thingName', **kwargs) 84 | payload = b'' 85 | 86 | return self._shadow_op('delete', thing_name, payload) 87 | 88 | def publish(self, **kwargs): 89 | r""" 90 | Publishes state information. 91 | 92 | :Keyword Arguments: 93 | * *topic* (``string``) -- 94 | [REQUIRED] 95 | The name of the MQTT topic. 96 | * *payload* (``bytes or seekable file-like object``) -- 97 | The state information, in JSON format. 98 | * *queueFullPolicy* (``string``) -- 99 | The policy for GGC to take when its internal queue is full 100 | :returns: None 101 | """ 102 | 103 | topic = self._get_required_parameter('topic', **kwargs) 104 | 105 | # payload and queueFullPolicy are optional parameters 106 | payload = kwargs.get('payload', b'') 107 | queue_full_policy = kwargs.get('queueFullPolicy', '') 108 | 109 | function_arn = ROUTER_FUNCTION_ARN 110 | client_context = { 111 | 'custom': { 112 | 'source': MY_FUNCTION_ARN, 113 | 'subject': topic 114 | } 115 | } 116 | 117 | if queue_full_policy == 'AllOrException': 118 | client_context['custom']['queueFullPolicy'] = 'AllOrError' 119 | elif queue_full_policy in ['BestEffort', '']: 120 | client_context['custom']['queueFullPolicy'] = queue_full_policy 121 | else: 122 | raise ValueError('Invalid value for queueFullPolicy: {queueFullPolicy}'.format( 123 | queueFullPolicy=queue_full_policy 124 | )) 125 | 126 | customer_logger.debug('Publishing message on topic "{}" with Payload "{}"'.format(topic, payload)) 127 | self.lambda_client._invoke_internal( 128 | function_arn, 129 | payload, 130 | base64.b64encode(json.dumps(client_context).encode()), 131 | 'Event' 132 | ) 133 | 134 | def _get_required_parameter(self, parameter_name, **kwargs): 135 | if parameter_name not in kwargs: 136 | raise ValueError('Parameter "{parameter_name}" is a required parameter but was not provided.'.format( 137 | parameter_name=parameter_name 138 | )) 139 | return kwargs[parameter_name] 140 | 141 | def _shadow_op(self, op, thing_name, payload): 142 | topic = '$aws/things/{thing_name}/shadow/{op}'.format(thing_name=thing_name, op=op) 143 | function_arn = SHADOW_FUNCTION_ARN 144 | client_context = { 145 | 'custom': { 146 | 'subject': topic 147 | } 148 | } 149 | 150 | customer_logger.debug('Calling shadow service on topic "{}" with payload "{}"'.format(topic, payload)) 151 | response = self.lambda_client._invoke_internal( 152 | function_arn, 153 | payload, 154 | base64.b64encode(json.dumps(client_context).encode()) 155 | ) 156 | 157 | if response['FunctionError'] != '': 158 | raise ShadowError('Request for shadow state returned FunctionError "{}" with error payload "{}"'.format( 159 | response['FunctionError'], response['Payload'] 160 | )) 161 | 162 | payload = response['Payload'].read() 163 | if response: 164 | response_payload_map = json.loads(payload.decode('utf-8')) 165 | if 'code' in response_payload_map and 'message' in response_payload_map: 166 | raise ShadowError('Request for shadow state returned error code {} with message "{}"'.format( 167 | response_payload_map['code'], response_payload_map['message'] 168 | )) 169 | 170 | return {'payload': payload} 171 | -------------------------------------------------------------------------------- /docs/_apidoc/modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | API Reference — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 93 | 94 |
95 | 96 | 97 | 103 | 104 | 105 |
106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 |
    128 | 129 |
  • Docs »
  • 130 | 131 |
  • API Reference
  • 132 | 133 | 134 |
  • 135 | 136 | 137 | View page source 138 | 139 | 140 |
  • 141 | 142 |
143 | 144 | 145 |
146 |
147 |
148 |
149 | 150 |
151 |

API Reference

152 | 178 |
179 | 180 | 181 |
182 | 183 |
184 |
185 | 186 | 187 |
188 | 189 |
190 |

191 | © Copyright 2022, Amazon.com. 192 | 193 |

194 |
195 | Built with Sphinx using a theme provided by Read the Docs. 196 | 197 |
198 | 199 |
200 |
201 | 202 |
203 | 204 |
205 | 206 | 207 | 208 | 209 | 210 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /docs/_apidoc/greengrasssdk.stream_manager.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.stream_manager package — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 97 | 98 |
99 | 100 | 101 | 107 | 108 | 109 |
110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
130 | 131 |
    132 | 133 |
  • Docs »
  • 134 | 135 |
  • greengrasssdk.stream_manager package
  • 136 | 137 | 138 |
  • 139 | 140 | 141 | View page source 142 | 143 | 144 |
  • 145 | 146 |
147 | 148 | 149 |
150 |
151 |
152 |
153 | 154 |
155 |

greengrasssdk.stream_manager package

156 |

Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 157 | SPDX-License-Identifier: Apache-2.0

158 |
159 |

Subpackages

160 | 165 |
166 | 177 |
178 | 179 | 180 |
181 | 182 |
183 |
184 | 185 | 186 |
187 | 188 |
189 |

190 | © Copyright 2022, Amazon.com. 191 | 192 |

193 |
194 | Built with Sphinx using a theme provided by Read the Docs. 195 | 196 |
197 | 198 |
199 |
200 | 201 |
202 | 203 |
204 | 205 | 206 | 207 | 208 | 209 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /docs/_apidoc/greengrasssdk.stream_manager.util.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.stream_manager.util module — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 93 | 94 |
95 | 96 | 97 | 103 | 104 | 105 |
106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 |
    128 | 129 |
  • Docs »
  • 130 | 131 |
  • greengrasssdk.stream_manager.util module
  • 132 | 133 | 134 |
  • 135 | 136 | 137 | View page source 138 | 139 | 140 |
  • 141 | 142 |
143 | 144 | 145 |
146 |
147 |
148 |
149 | 150 |
151 |

greengrasssdk.stream_manager.util module

152 |

Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 153 | SPDX-License-Identifier: Apache-2.0

154 |
155 |
156 | class greengrasssdk.stream_manager.util.Util[source]
157 |

Bases: object

158 |

Validate And Serialize an instance of class to Json bytes. 159 | :param data: an instance object 160 | :return: a byte array. 161 | :raises: :ValidationException

162 |
163 |
164 | static validate_and_serialize_to_json_bytes(data)[source]
165 |
166 | 167 |
168 |
169 | static deserialize_json_bytes_to_obj(bytes, type)[source]
170 |
171 | 172 |
173 | 174 |
175 | 176 | 177 |
178 | 179 |
180 |
181 | 182 | 183 |
184 | 185 |
186 |

187 | © Copyright 2022, Amazon.com. 188 | 189 |

190 |
191 | Built with Sphinx using a theme provided by Read the Docs. 192 | 193 |
194 | 195 |
196 |
197 | 198 |
199 | 200 |
201 | 202 | 203 | 204 | 205 | 206 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /docs/_modules/greengrasssdk/client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.client — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 90 | 91 |
92 | 93 | 94 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
123 | 124 |
    125 | 126 |
  • Docs »
  • 127 | 128 |
  • Module code »
  • 129 | 130 |
  • greengrasssdk.client
  • 131 | 132 | 133 |
  • 134 | 135 |
  • 136 | 137 |
138 | 139 | 140 |
141 |
142 |
143 |
144 | 145 |

Source code for greengrasssdk.client

146 | #
147 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
148 | #
149 | 
150 | 
151 | 
[docs]def client(client_type, *args, **kwargs): 152 | if client_type == 'lambda': 153 | from .Lambda import Client 154 | elif client_type == 'iot-data': 155 | from .IoTDataPlane import Client 156 | elif client_type == 'secretsmanager': 157 | from .SecretsManager import Client 158 | elif client_type == 'streammanager': 159 | from .stream_manager import StreamManagerClient as Client 160 | else: 161 | raise Exception('Client type {} is not recognized.'.format(repr(client_type))) 162 | 163 | return Client(*args, **kwargs)
164 |
165 | 166 |
167 | 168 |
169 |
170 | 171 | 172 |
173 | 174 |
175 |

176 | © Copyright 2022, Amazon.com. 177 | 178 |

179 |
180 | Built with Sphinx using a theme provided by Read the Docs. 181 | 182 |
183 | 184 |
185 |
186 | 187 |
188 | 189 |
190 | 191 | 192 | 193 | 194 | 195 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /docs/_apidoc/greengrasssdk.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk package — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 97 | 98 |
99 | 100 | 101 | 107 | 108 | 109 |
110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
130 | 131 |
    132 | 133 |
  • Docs »
  • 134 | 135 |
  • greengrasssdk package
  • 136 | 137 | 138 |
  • 139 | 140 | 141 | View page source 142 | 143 | 144 |
  • 145 | 146 |
147 | 148 | 149 |
150 |
151 |
152 |
153 | 154 | 196 | 197 | 198 |
199 | 200 |
201 |
202 | 203 | 204 |
205 | 206 |
207 |

208 | © Copyright 2022, Amazon.com. 209 | 210 |

211 |
212 | Built with Sphinx using a theme provided by Read the Docs. 213 | 214 |
215 | 216 |
217 |
218 | 219 |
220 | 221 |
222 | 223 | 224 | 225 | 226 | 227 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 252 | 253 | 254 | -------------------------------------------------------------------------------- /greengrasssdk/SecretsManager.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | from __future__ import division 6 | import json 7 | import logging 8 | from datetime import datetime 9 | 10 | from greengrasssdk import Lambda 11 | from greengrass_common.env_vars import MY_FUNCTION_ARN, SECRETS_MANAGER_FUNCTION_ARN 12 | 13 | # Log messages in the SDK are part of customer's log because they're helpful for debugging 14 | # customer's lambdas. Since we configured the root logger to log to customer's log and set the 15 | # propagate flag of this logger to True. The log messages submitted from this logger will be 16 | # sent to the customer's local Cloudwatch handler. 17 | customer_logger = logging.getLogger(__name__) 18 | customer_logger.propagate = True 19 | 20 | KEY_NAME_PAYLOAD = 'Payload' 21 | KEY_NAME_STATUS = 'Status' 22 | KEY_NAME_MESSAGE = 'Message' 23 | KEY_NAME_SECRET_ID = 'SecretId' 24 | KEY_NAME_VERSION_ID = 'VersionId' 25 | KEY_NAME_VERSION_STAGE = 'VersionStage' 26 | KEY_NAME_CREATED_DATE = "CreatedDate" 27 | 28 | 29 | class SecretsManagerError(Exception): 30 | pass 31 | 32 | 33 | class Client: 34 | def __init__(self): 35 | self.lambda_client = Lambda.Client() 36 | 37 | def get_secret_value(self, **kwargs): 38 | r""" 39 | Call secrets manager lambda to obtain the requested secret value. 40 | 41 | :Keyword Arguments: 42 | * *SecretId* (``string``) -- 43 | [REQUIRED] 44 | Specifies the secret containing the version that you want to retrieve. You can specify either the 45 | Amazon Resource Name (ARN) or the friendly name of the secret. 46 | * *VersionId* (``string``) -- 47 | Specifies the unique identifier of the version of the secret that you want to retrieve. If you 48 | specify this parameter then don't specify ``VersionStage`` . If you don't specify either a 49 | ``VersionStage`` or ``SecretVersionId`` then the default is to perform the operation on the version 50 | with the ``VersionStage`` value of ``AWSCURRENT`` . 51 | 52 | This value is typically a UUID-type value with 32 hexadecimal digits. 53 | * *VersionStage* (``string``) -- 54 | Specifies the secret version that you want to retrieve by the staging label attached to the 55 | version. 56 | 57 | Staging labels are used to keep track of different versions during the rotation process. If you 58 | use this parameter then don't specify ``SecretVersionId`` . If you don't specify either a 59 | ``VersionStage`` or ``SecretVersionId`` , then the default is to perform the operation on the 60 | version with the ``VersionStage`` value of ``AWSCURRENT`` . 61 | 62 | :returns: (``dict``) -- 63 | * *ARN* (``string``) -- 64 | The ARN of the secret. 65 | * *Name* (``string``) -- 66 | The friendly name of the secret. 67 | * *VersionId* (``string``) -- 68 | The unique identifier of this version of the secret. 69 | * *SecretBinary* (``bytes``) -- 70 | The decrypted part of the protected secret information that was originally provided as 71 | binary data in the form of a byte array. The response parameter represents the binary data 72 | as a base64-encoded string. 73 | 74 | This parameter is not used if the secret is created by the Secrets Manager console. 75 | 76 | If you store custom information in this field of the secret, then you must code your Lambda 77 | rotation function to parse and interpret whatever you store in the ``SecretString`` or 78 | ``SecretBinary`` fields. 79 | * *SecretString* (``string``) -- 80 | The decrypted part of the protected secret information that was originally provided as a 81 | string. 82 | 83 | If you create this secret by using the Secrets Manager console then only the ``SecretString`` 84 | parameter contains data. Secrets Manager stores the information as a JSON structure of 85 | key/value pairs that the Lambda rotation function knows how to parse. 86 | 87 | If you store custom information in the secret by using the CreateSecret , UpdateSecret , or 88 | PutSecretValue API operations instead of the Secrets Manager console, or by using the 89 | *Other secret type* in the console, then you must code your Lambda rotation function to 90 | parse and interpret those values. 91 | * *VersionStages* (``list``) -- 92 | A list of all of the staging labels currently attached to this version of the secret. 93 | * (``string``) -- 94 | * *CreatedDate* (``datetime``) -- 95 | The date and time that this version of the secret was created. 96 | """ 97 | 98 | secret_id = self._get_required_parameter(KEY_NAME_SECRET_ID, **kwargs) 99 | version_id = kwargs.get(KEY_NAME_VERSION_ID, '') 100 | version_stage = kwargs.get(KEY_NAME_VERSION_STAGE, '') 101 | 102 | if version_id: # TODO: Remove this once we support query by VersionId 103 | raise SecretsManagerError('Query by VersionId is not yet supported') 104 | if version_id and version_stage: 105 | raise ValueError('VersionId and VersionStage cannot both be specified at the same time') 106 | 107 | request_payload_bytes = self._generate_request_payload_bytes(secret_id=secret_id, 108 | version_id=version_id, 109 | version_stage=version_stage) 110 | 111 | customer_logger.debug('Retrieving secret value with id "{}", version id "{}" version stage "{}"' 112 | .format(secret_id, version_id, version_stage)) 113 | response = self.lambda_client._invoke_internal( 114 | SECRETS_MANAGER_FUNCTION_ARN, 115 | request_payload_bytes, 116 | b'', # We do not need client context for Secrets Manager back-end lambda 117 | ) # Use Request/Response here as we are mimicking boto3 Http APIs for SecretsManagerService 118 | 119 | payload = response[KEY_NAME_PAYLOAD].read() 120 | payload_dict = json.loads(payload.decode('utf-8')) 121 | 122 | # All customer facing errors are presented within the response payload. For example: 123 | # { 124 | # "code": 404, 125 | # "message": "Resource not found" 126 | # } 127 | if KEY_NAME_STATUS in payload_dict and KEY_NAME_MESSAGE in payload_dict: 128 | raise SecretsManagerError('Request for secret value returned error code {} with message {}'.format( 129 | payload_dict[KEY_NAME_STATUS], payload_dict[KEY_NAME_MESSAGE] 130 | )) 131 | 132 | # Time is serialized as epoch timestamp (int) upon IPC routing. We need to deserialize it back to datetime object in Python 133 | payload_dict[KEY_NAME_CREATED_DATE] = datetime.fromtimestamp( 134 | # Cloud response contains timestamp in milliseconds while datetime.fromtimestamp is expecting seconds 135 | payload_dict[KEY_NAME_CREATED_DATE] / 1000 136 | ) 137 | 138 | return payload_dict 139 | 140 | def _generate_request_payload_bytes(self, secret_id, version_id, version_stage): 141 | request_payload = { 142 | KEY_NAME_SECRET_ID: secret_id, 143 | } 144 | if version_stage: 145 | request_payload[KEY_NAME_VERSION_STAGE] = version_stage 146 | 147 | # TODO: Add VersionId once we support query by VersionId 148 | 149 | # The allowed chars for secret id and version stage are strictly enforced when customers are configuring them 150 | # through Secrets Manager Service in the cloud: 151 | # https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html#API_CreateSecret_RequestSyntax 152 | return json.dumps(request_payload).encode() 153 | 154 | @staticmethod 155 | def _get_required_parameter(parameter_name, **kwargs): 156 | if parameter_name not in kwargs: 157 | raise ValueError('Parameter "{parameter_name}" is a required parameter but was not provided.'.format( 158 | parameter_name=parameter_name 159 | )) 160 | return kwargs[parameter_name] 161 | -------------------------------------------------------------------------------- /greengrasssdk/Lambda.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | 5 | import logging 6 | import re 7 | 8 | from io import BytesIO 9 | 10 | from greengrass_common.function_arn_fields import FunctionArnFields 11 | from greengrass_ipc_python_sdk.ipc_client import IPCClient, IPCException 12 | from greengrasssdk.utils.testing import mock 13 | 14 | # Log messages in the SDK are part of customer's log because they're helpful for debugging 15 | # customer's lambdas. Since we configured the root logger to log to customer's log and set the 16 | # propagate flag of this logger to True. The log messages submitted from this logger will be 17 | # sent to the customer's local Cloudwatch handler. 18 | customer_logger = logging.getLogger(__name__) 19 | customer_logger.propagate = True 20 | 21 | valid_base64_regex = '^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$' 22 | 23 | 24 | class InvocationException(Exception): 25 | pass 26 | 27 | 28 | class Client: 29 | def __init__(self, endpoint='localhost', port=None): 30 | """ 31 | :param endpoint: Endpoint used to connect to IPC. 32 | :type endpoint: str 33 | 34 | :param port: Deprecated. Will not be used. 35 | :type port: None 36 | """ 37 | self.ipc = IPCClient(endpoint=endpoint) 38 | 39 | def invoke(self, **kwargs): 40 | r""" 41 | Invokes Lambda function of the given name. 42 | 43 | :Keyword Arguments: 44 | * *ClientContext* (``bytes``) -- 45 | Optional Base64-encoded data about the invoking client to pass to the Lambda function 46 | * *FunctionName* (``string``) -- 47 | [REQUIRED] 48 | The Amazon Resource Name (ARN) of the Lambda function to invoke. Name formats: 49 | 50 | * Qualified ARN - The function ARN with the version suffix. e.g. arn:aws:lambda:aws-region:acct-id:function:helloworld:1 51 | * Unqualified ARN - The function ARN without the version suffix. e.g. arn:aws:lambda:aws-region:acct-id:function:helloworld 52 | * *InvocationType* (``string``) -- 53 | Choose from the following options. 54 | 55 | * ``RequestResponse`` (default) - Invoke the Lambda synchronously. Block until the function returns a response or times out. 56 | * ``Event`` - Invoke the Lambda asynchronously. The response only includes empty payload. 57 | * *Payload* (``bytes``) -- 58 | Optional input for the Lambda function to invoke. 59 | * *Qualifier* (``string``) -- 60 | Optional parameter to specify a Lambda function version if it was not included in the FunctionName field. 61 | If you specify a function version, the API uses the qualified function ARN to invoke a specific Lambda function. 62 | :returns: (``dict``) -- 63 | * *FunctionError* (``string``) -- 64 | If present, indicates that an error occurred while executing the Lambda function. If an error occurred, 65 | this field will have one of two values, ``Handled`` or ``Unhandled``. ``Handled`` errors are errors that are reported by the function 66 | while the ``Unhandled`` errors are those detected and reported by Greengrass Core. 67 | ``Unhandled`` errors include out of memory errors and function timeouts. Error details are provided in the Payload. 68 | * *Payload* (``bytes or StreamingBody object``) -- 69 | It is the result returned by the Lambda function. This is present only if the invocation type is ``RequestResponse``. 70 | In the event of a function error this field contains a message describing the error. 71 | """ 72 | 73 | # FunctionName is a required parameter 74 | if 'FunctionName' not in kwargs: 75 | raise ValueError( 76 | '"FunctionName" argument of Lambda.Client.invoke is a required argument but was not provided.' 77 | ) 78 | 79 | arn_fields = FunctionArnFields(kwargs['FunctionName']) 80 | arn_qualifier = arn_fields.qualifier 81 | 82 | # A Function qualifier can be provided as part of the ARN in FunctionName, or it can be provided here. The 83 | # behavior of the cloud is to throw an exception if both are specified but not equal 84 | extraneous_qualifier = kwargs.get('Qualifier', '') 85 | 86 | if extraneous_qualifier and arn_qualifier and arn_qualifier != extraneous_qualifier: 87 | raise ValueError('The derived qualifier from the function name does not match the specified qualifier.') 88 | 89 | final_qualifier = arn_qualifier if arn_qualifier else extraneous_qualifier 90 | 91 | try: 92 | # GGC v1.9.0 or newer 93 | function_arn = FunctionArnFields.build_function_arn(arn_fields.unqualified_arn, final_qualifier) 94 | except AttributeError: 95 | # older GGC version 96 | raise AttributeError('class FunctionArnFields has no attribute \'build_function_arn\'. build_function_arn ' 97 | 'is introduced in GGC v1.9.0. Please check your GGC version.') 98 | 99 | # ClientContext must be base64 if given, but is an option parameter 100 | try: 101 | client_context = kwargs.get('ClientContext', b'').decode() 102 | except AttributeError as e: 103 | customer_logger.exception(e) 104 | raise ValueError( 105 | '"ClientContext" argument must be a byte string or support a decode method which returns a string' 106 | ) 107 | 108 | if client_context: 109 | if not re.match(valid_base64_regex, client_context): 110 | raise ValueError('"ClientContext" argument of Lambda.Client.invoke must be base64 encoded.') 111 | 112 | # Payload is an optional parameter 113 | payload = kwargs.get('Payload', b'') 114 | invocation_type = kwargs.get('InvocationType', 'RequestResponse') 115 | customer_logger.debug('Invoking local lambda "{}" with payload "{}" and client context "{}"'.format( 116 | function_arn, payload, client_context)) 117 | 118 | # Post the work to IPC and return the result of that work 119 | return self._invoke_internal(function_arn, payload, client_context, invocation_type) 120 | 121 | @mock 122 | def _invoke_internal(self, function_arn, payload, client_context, invocation_type="RequestResponse"): 123 | """ 124 | This private method is seperate from the main, public invoke method so that other code within this SDK can 125 | give this Lambda client a raw payload/client context to invoke with, rather than having it built for them. 126 | This lets you include custom ExtensionMap_ values like subject which are needed for our internal pinned Lambdas. 127 | """ 128 | customer_logger.debug('Invoking Lambda function "{}" with Greengrass Message "{}"'.format(function_arn, payload)) 129 | 130 | try: 131 | invocation_id = self.ipc.post_work(function_arn, payload, client_context, invocation_type) 132 | 133 | if invocation_type == "Event": 134 | # TODO: Properly return errors based on BOTO response 135 | # https://boto3.readthedocs.io/en/latest/reference/services/lambda.html#Lambda.Client.invoke 136 | return {'Payload': b'', 'FunctionError': ''} 137 | 138 | work_result_output = self.ipc.get_work_result(function_arn, invocation_id) 139 | if not work_result_output.func_err: 140 | output_payload = StreamingBody(work_result_output.payload) 141 | else: 142 | output_payload = work_result_output.payload 143 | invoke_output = { 144 | 'Payload': output_payload, 145 | 'FunctionError': work_result_output.func_err, 146 | } 147 | return invoke_output 148 | except IPCException as e: 149 | customer_logger.exception(e) 150 | raise InvocationException('Failed to invoke function due to ' + str(e)) 151 | 152 | 153 | class StreamingBody(object): 154 | """Wrapper class for http response payload 155 | 156 | This provides a consistent interface to AWS Lambda Python SDK 157 | """ 158 | def __init__(self, payload): 159 | self._raw_stream = BytesIO(payload) 160 | self._amount_read = 0 161 | 162 | def read(self, amt=None): 163 | """Read at most amt bytes from the stream. 164 | If the amt argument is omitted, read all data. 165 | """ 166 | chunk = self._raw_stream.read(amt) 167 | self._amount_read += len(chunk) 168 | return chunk 169 | 170 | def close(self): 171 | self._raw_stream.close() 172 | -------------------------------------------------------------------------------- /docs/py-modindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Python Module Index — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 | 46 | 93 | 94 |
95 | 96 | 97 | 103 | 104 | 105 |
106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 |
    128 | 129 |
  • Docs »
  • 130 | 131 |
  • Python Module Index
  • 132 | 133 | 134 |
  • 135 | 136 |
  • 137 | 138 |
139 | 140 | 141 |
142 |
143 |
144 |
145 | 146 | 147 |

Python Module Index

148 | 149 |
150 | g 151 |
152 | 153 | 154 | 155 | 157 | 158 | 160 | 163 | 164 | 165 | 168 | 169 | 170 | 173 | 174 | 175 | 178 | 179 | 180 | 183 | 184 | 185 | 188 | 189 | 190 | 193 | 194 | 195 | 198 | 199 | 200 | 203 | 204 | 205 | 208 | 209 | 210 | 213 | 214 | 215 | 218 | 219 | 220 | 223 |
 
156 | g
161 | greengrasssdk 162 |
    166 | greengrasssdk.client 167 |
    171 | greengrasssdk.IoTDataPlane 172 |
    176 | greengrasssdk.Lambda 177 |
    181 | greengrasssdk.SecretsManager 182 |
    186 | greengrasssdk.stream_manager 187 |
    191 | greengrasssdk.stream_manager.data 192 |
    196 | greengrasssdk.stream_manager.exceptions 197 |
    201 | greengrasssdk.stream_manager.streammanagerclient 202 |
    206 | greengrasssdk.stream_manager.util 207 |
    211 | greengrasssdk.stream_manager.utilinternal 212 |
    216 | greengrasssdk.utils 217 |
    221 | greengrasssdk.utils.testing 222 |
224 | 225 | 226 |
227 | 228 |
229 |
230 | 231 | 232 |
233 | 234 |
235 |

236 | © Copyright 2022, Amazon.com. 237 | 238 |

239 |
240 | Built with Sphinx using a theme provided by Read the Docs. 241 | 242 |
243 | 244 |
245 |
246 | 247 |
248 | 249 |
250 | 251 | 252 | 253 | 254 | 255 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /docs/_modules/greengrasssdk/stream_manager/util.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.stream_manager.util — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 90 | 91 |
92 | 93 | 94 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
123 | 124 |
    125 | 126 |
  • Docs »
  • 127 | 128 |
  • Module code »
  • 129 | 130 |
  • greengrasssdk.stream_manager.util
  • 131 | 132 | 133 |
  • 134 | 135 |
  • 136 | 137 |
138 | 139 | 140 |
141 |
142 |
143 |
144 | 145 |

Source code for greengrasssdk.stream_manager.util

146 | """
147 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
148 | SPDX-License-Identifier: Apache-2.0
149 | """
150 | 
151 | import json
152 | 
153 | from .exceptions import ValidationException
154 | from .utilinternal import UtilInternal
155 | 
156 | 
157 | """
158 | Util functions exposed to the customers
159 | """
160 | 
161 | 
162 | 
[docs]class Util: 163 | """ 164 | Validate And Serialize an instance of class to Json bytes. 165 | :param data: an instance object 166 | :return: a byte array. 167 | :raises: :ValidationException 168 | """ 169 | 170 |
[docs] @staticmethod 171 | def validate_and_serialize_to_json_bytes(data): 172 | validation = UtilInternal.is_invalid(data) 173 | if validation: 174 | raise ValidationException(validation) 175 | return UtilInternal.serialize_to_json_with_empty_array_as_null(data)
176 | 177 | """ 178 | Deserialize the json byte array to an object 179 | :param :bytes byte array of data 180 | :param :type instance class type 181 | :return: an object. 182 | """ 183 | 184 |
[docs] @staticmethod 185 | def deserialize_json_bytes_to_obj(bytes, type): 186 | return type.from_dict(json.loads(bytes))
187 |
188 | 189 |
190 | 191 |
192 |
193 | 194 | 195 |
196 | 197 |
198 |

199 | © Copyright 2022, Amazon.com. 200 | 201 |

202 |
203 | Built with Sphinx using a theme provided by Read the Docs. 204 | 205 |
206 | 207 |
208 |
209 | 210 |
211 | 212 |
213 | 214 | 215 | 216 | 217 | 218 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /docs/_modules/greengrasssdk/utils/testing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | greengrasssdk.utils.testing — Greengrass Core Python SDK 1.6.1 documentation 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 90 | 91 |
92 | 93 | 94 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
123 | 124 |
    125 | 126 |
  • Docs »
  • 127 | 128 |
  • Module code »
  • 129 | 130 |
  • greengrasssdk.utils.testing
  • 131 | 132 | 133 |
  • 134 | 135 |
  • 136 | 137 |
138 | 139 | 140 |
141 |
142 |
143 |
144 | 145 |

Source code for greengrasssdk.utils.testing

146 | #
147 | # Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
148 | #
149 | 
150 | import json
151 | from functools import wraps
152 | from greengrass_common.env_vars import MY_FUNCTION_ARN
153 | 
154 | 
155 | 
[docs]def mock(func): 156 | """ 157 | mock decorates _invoke_internal by checking if MY_FUNCTION_ARN is present 158 | if MY_FUNCTION_ARN is present, the actual _invoke_internal is invoked 159 | otherwise, the mock _invoke_internal is invoked 160 | """ 161 | @wraps(func) 162 | def mock_invoke_internal(self, function_arn, payload, client_context, invocation_type="RequestResponse"): 163 | if MY_FUNCTION_ARN is None: 164 | if invocation_type == 'RequestResponse': 165 | return { 166 | 'Payload': json.dumps({ 167 | 'TestKey': 'TestValue' 168 | }), 169 | 'FunctionError': '' 170 | } 171 | elif invocation_type == 'Event': 172 | return { 173 | 'Payload': b'', 174 | 'FunctionError': '' 175 | } 176 | else: 177 | raise Exception('Unsupported invocation type {}'.format(invocation_type)) 178 | else: 179 | return func(self, function_arn, payload, client_context, invocation_type) 180 | return mock_invoke_internal
181 |
182 | 183 |
184 | 185 |
186 |
187 | 188 | 189 |
190 | 191 |
192 |

193 | © Copyright 2022, Amazon.com. 194 | 195 |

196 |
197 | Built with Sphinx using a theme provided by Read the Docs. 198 | 199 |
200 | 201 |
202 |
203 | 204 |
205 | 206 |
207 | 208 | 209 | 210 | 211 | 212 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /examples/TrafficLight/lightController.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | # 4 | # This Greengrass example simulates a traffic light (using a switch and light) 5 | # cycling between G, Y, R by updating the desired property in the shadow. 6 | # Please refer to the AWS Greengrass Getting Started Guide, Module 5 for more information. 7 | # 8 | # This file is meant to be used in conjunction with trafficLight.py 9 | 10 | import argparse 11 | import json 12 | import logging 13 | import os 14 | import re 15 | import sys 16 | import time 17 | from itertools import cycle 18 | 19 | from AWSIoTPythonSDK.core.greengrass.discovery.providers import DiscoveryInfoProvider 20 | from AWSIoTPythonSDK.core.protocol.connection.cores import ProgressiveBackOffCore 21 | from AWSIoTPythonSDK.exception.AWSIoTExceptions import DiscoveryInvalidRequestException 22 | from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient 23 | 24 | MAX_DISCOVERY_RETRIES = 10 # MAX tries at discovery before giving up 25 | GROUP_PATH = "./groupCA/" # directory storing discovery info 26 | CA_NAME = "root-ca.crt" # stores GGC CA cert 27 | GGC_ADDR_NAME = "ggc-host" # stores GGC host address 28 | 29 | 30 | # Shadow JSON schema: 31 | # 32 | # Name: Bot 33 | # { 34 | # "state": { 35 | # "desired":{ 36 | # "property": 37 | # } 38 | # } 39 | # } 40 | 41 | # Custom Shadow callback for updating the desired state in the shadow 42 | def customShadowCallback_Update(payload, responseStatus, token): 43 | # payload is a JSON string ready to be parsed using json.loads(...) 44 | # in both Py2.x and Py3.x 45 | if responseStatus == "timeout": 46 | print("Update request " + token + " time out!") 47 | if responseStatus == "accepted": 48 | payloadDict = json.loads(payload) 49 | print("~~~~~~~~~~Shadow Update Accepted~~~~~~~~~~~~~") 50 | print("Update request with token: " + token + " accepted!") 51 | print("property: " + str(payloadDict["state"]["desired"]["property"])) 52 | print("~~~~~~~~~~~~~~~~~~~~~~~\n\n") 53 | if responseStatus == "rejected": 54 | print("Update request " + token + " rejected!") 55 | 56 | 57 | # function does basic regex check to see if value might be an ip address 58 | def isIpAddress(value): 59 | match = re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}", value) 60 | if match: 61 | return True 62 | return False 63 | 64 | 65 | # function reads host GGC ip address from filePath 66 | def getGGCAddr(filePath): 67 | f = open(filePath, "r") 68 | return f.readline() 69 | 70 | 71 | # Used to discover GGC group CA and end point. After discovering it persists in GROUP_PATH 72 | def discoverGGC(host, iotCAPath, certificatePath, privateKeyPath, clientId): 73 | # Progressive back off core 74 | backOffCore = ProgressiveBackOffCore() 75 | 76 | # Discover GGCs 77 | discoveryInfoProvider = DiscoveryInfoProvider() 78 | discoveryInfoProvider.configureEndpoint(host) 79 | discoveryInfoProvider.configureCredentials(iotCAPath, certificatePath, privateKeyPath) 80 | discoveryInfoProvider.configureTimeout(10) # 10 sec 81 | print("Iot end point: " + host) 82 | print("Iot CA Path: " + iotCAPath) 83 | print("GGAD cert path: " + certificatePath) 84 | print("GGAD private key path: " + privateKeyPath) 85 | print("GGAD thing name : " + clientId) 86 | retryCount = MAX_DISCOVERY_RETRIES 87 | discovered = False 88 | groupCA = None 89 | coreInfo = None 90 | while retryCount != 0: 91 | try: 92 | discoveryInfo = discoveryInfoProvider.discover(clientId) 93 | caList = discoveryInfo.getAllCas() 94 | coreList = discoveryInfo.getAllCores() 95 | 96 | # In this example we have one core 97 | # So we only pick the first ca and core info 98 | groupId, ca = caList[0] 99 | coreInfo = coreList[0] 100 | print("Discovered GGC: " + coreInfo.coreThingArn + " from Group: " + groupId) 101 | hostAddr = "" 102 | 103 | # In this example Ip detector lambda is turned on which reports 104 | # the GGC hostAddr to the CIS (Connectivity Information Service) that stores the 105 | # connectivity information for the AWS Greengrass core associated with your group. 106 | # This is the information used by discovery and the list of host addresses 107 | # could be outdated or wrong and you would normally want to 108 | # validate it in a better way. 109 | # For simplicity, we will assume the first host address that looks like an ip 110 | # is the right one to connect to GGC. 111 | # Note: this can also be set manually via the update-connectivity-info CLI 112 | for addr in coreInfo.connectivityInfoList: 113 | hostAddr = addr.host 114 | if isIpAddress(hostAddr): 115 | break 116 | 117 | print("Discovered GGC Host Address: " + hostAddr) 118 | print("Now we persist the connectivity/identity information...") 119 | groupCA = GROUP_PATH + CA_NAME 120 | ggcHostPath = GROUP_PATH + GGC_ADDR_NAME 121 | if not os.path.exists(GROUP_PATH): 122 | os.makedirs(GROUP_PATH) 123 | groupCAFile = open(groupCA, "w") 124 | groupCAFile.write(ca) 125 | groupCAFile.close() 126 | groupHostFile = open(ggcHostPath, "w") 127 | groupHostFile.write(hostAddr) 128 | groupHostFile.close() 129 | 130 | discovered = True 131 | print("Now proceed to the connecting flow...") 132 | break 133 | except DiscoveryInvalidRequestException as e: 134 | print("Invalid discovery request detected!") 135 | print("Type: " + str(type(e))) 136 | print("Error message: " + e.message) 137 | print("Stopping...") 138 | break 139 | except BaseException as e: 140 | print("Error in discovery!") 141 | print("Type: " + str(type(e))) 142 | print("Error message: " + e.message) 143 | retryCount -= 1 144 | print("\n" + str(retryCount) + "/" + str(MAX_DISCOVERY_RETRIES) + " retries left\n") 145 | print("Backing off...\n") 146 | backOffCore.backOff() 147 | 148 | if not discovered: 149 | print("Discovery failed after " + str(MAX_DISCOVERY_RETRIES) + " retries. Exiting...\n") 150 | sys.exit(-1) 151 | 152 | 153 | # Read in command-line parameters 154 | parser = argparse.ArgumentParser() 155 | parser.add_argument("-e", "--endpoint", action="store", required=True, dest="host", help="Your AWS IoT custom endpoint") 156 | parser.add_argument("-r", "--rootCA", action="store", required=True, dest="rootCAPath", help="Root CA file path") 157 | parser.add_argument("-c", "--cert", action="store", dest="certificatePath", help="Certificate file path") 158 | parser.add_argument("-k", "--key", action="store", dest="privateKeyPath", help="Private key file path") 159 | parser.add_argument("-n", "--thingName", action="store", dest="thingName", default="Bot", help="Targeted thing name") 160 | parser.add_argument( 161 | "-id", "--clientId", action="store", dest="clientId", default="lightController", help="Targeted client id" 162 | ) 163 | 164 | args = parser.parse_args() 165 | host = args.host 166 | iotCAPath = args.rootCAPath 167 | certificatePath = args.certificatePath 168 | privateKeyPath = args.privateKeyPath 169 | thingName = args.thingName 170 | clientId = args.clientId 171 | 172 | # Configure logging 173 | logger = logging.getLogger("AWSIoTPythonSDK.core") 174 | logger.setLevel(logging.INFO) # set to logging.DEBUG for additional logging 175 | streamHandler = logging.StreamHandler() 176 | formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") 177 | streamHandler.setFormatter(formatter) 178 | logger.addHandler(streamHandler) 179 | 180 | # Run Discovery service to check which GGC to connect to, if it hasn't been run already 181 | # Discovery talks with the IoT cloud to get the GGC CA cert and ip address 182 | 183 | if not os.path.isfile("./groupCA/root-ca.crt"): 184 | discoverGGC(host, iotCAPath, certificatePath, privateKeyPath, clientId) 185 | else: 186 | print("Greengrass core has already been discovered.") 187 | 188 | # read GGC Host Address from file 189 | ggcAddrPath = GROUP_PATH + GGC_ADDR_NAME 190 | rootCAPath = GROUP_PATH + CA_NAME 191 | ggcAddr = getGGCAddr(ggcAddrPath) 192 | print("GGC Host Address: " + ggcAddr) 193 | print("GGC Group CA Path: " + rootCAPath) 194 | print("Private Key of lightController thing Path: " + privateKeyPath) 195 | print("Certificate of lightController thing Path: " + certificatePath) 196 | print("Client ID(thing name for lightController): " + clientId) 197 | print("Target shadow thing ID(thing name for trafficLight): " + thingName) 198 | 199 | # Init AWSIoTMQTTShadowClient 200 | myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient(clientId) 201 | myAWSIoTMQTTShadowClient.configureEndpoint(ggcAddr, 8883) 202 | myAWSIoTMQTTShadowClient.configureCredentials(rootCAPath, privateKeyPath, certificatePath) 203 | 204 | # AWSIoTMQTTShadowClient configuration 205 | myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20) 206 | myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10) # 10 sec 207 | myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5) # 5 sec 208 | 209 | # Connect to AWS IoT 210 | myAWSIoTMQTTShadowClient.connect() 211 | 212 | # Create a deviceShadow with persistent subscription 213 | deviceShadowHandler = myAWSIoTMQTTShadowClient.createShadowHandlerWithName(thingName, True) 214 | 215 | # This loop simulates a traffic light cycling between G, Y, R by updating the desired property in the shadow 216 | # This uses the desired property because the light GGAD will get the request for changing and update the 217 | # reported property. The idea is the desired property is a request to update the light while the 218 | # reported property is the actual value of the light 219 | loopCount = 0 220 | states = ["G", "Y", "R"] 221 | pool = cycle(states) 222 | for item in pool: 223 | JSONPayload = '{"state":{"desired":{"property":' + '"' + item + '"}}}' 224 | print(JSONPayload) 225 | deviceShadowHandler.shadowUpdate(JSONPayload, customShadowCallback_Update, 5) 226 | loopCount += 1 227 | time.sleep(20) 228 | -------------------------------------------------------------------------------- /greengrasssdk/stream_manager/utilinternal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | """ 5 | 6 | import asyncio 7 | import json 8 | import re 9 | import uuid 10 | from typing import Sequence 11 | 12 | from .data import ResponseStatusCode 13 | from .exceptions import ( 14 | InvalidRequestException, 15 | MessageStoreReadErrorException, 16 | NotEnoughMessagesException, 17 | RequestPayloadTooLargeException, 18 | ResourceNotFoundException, 19 | ResponsePayloadTooLargeException, 20 | ServerOutOfMemoryException, 21 | ServerTimeoutException, 22 | StreamManagerException, 23 | UnauthorizedException, 24 | UnknownFailureException, 25 | UnknownOperationException, 26 | UpdateFailedException, 27 | UpdateNotAllowedException, 28 | ) 29 | 30 | 31 | class UtilInternal: 32 | __ENDIAN = "big" 33 | _MAX_PACKET_SIZE = 1 << 30 34 | 35 | @staticmethod 36 | def sync(coro, loop: asyncio.AbstractEventLoop): 37 | if asyncio.iscoroutine(coro): 38 | # Run async function in the loop and return the value or raise the exception 39 | return asyncio.run_coroutine_threadsafe(coro, loop=loop).result() 40 | 41 | return coro 42 | 43 | """ 44 | Delete keys with the value ``None`` in a dictionary, recursively. 45 | This alters the input so you may wish to ``copy`` the dict first. 46 | """ 47 | 48 | @staticmethod 49 | def del_empty_arrays(d): 50 | 51 | for key, value in list(d.items()): 52 | if isinstance(value, list) and len(value) == 0: 53 | del d[key] 54 | elif isinstance(value, dict): 55 | UtilInternal.del_empty_arrays(value) 56 | return d 57 | 58 | @staticmethod 59 | def serialize_to_json_with_empty_array_as_null(data): 60 | s = json.dumps(UtilInternal.del_empty_arrays(data.as_dict())) 61 | 62 | return s.encode() 63 | 64 | @staticmethod 65 | def int_to_bytes(i, length=4): 66 | return int.to_bytes(i, length=length, byteorder=UtilInternal.__ENDIAN, signed=True) 67 | 68 | @staticmethod 69 | def int_from_bytes(b): 70 | return int.from_bytes(b, byteorder=UtilInternal.__ENDIAN, signed=True) 71 | 72 | @staticmethod 73 | def encode_frame(frame) -> Sequence[bytes]: 74 | if len(frame.payload) + 1 > UtilInternal._MAX_PACKET_SIZE: 75 | raise RequestPayloadTooLargeException() 76 | return [ 77 | bytes( 78 | [ 79 | *UtilInternal.int_to_bytes(len(frame.payload) + 1), 80 | *UtilInternal.int_to_bytes(frame.operation.value, length=1), 81 | ] 82 | ), 83 | frame.payload, 84 | ] 85 | 86 | @staticmethod 87 | def get_request_id(): 88 | return str(uuid.uuid4()) 89 | 90 | @staticmethod 91 | def is_invalid(o): 92 | if not hasattr(o, "_validations_map"): 93 | return False 94 | if not hasattr(o, "_types_map"): 95 | return False 96 | for prop_name, validations in o._validations_map.items(): 97 | if not hasattr(o, prop_name): 98 | return "Object is malformed, missing property: {}".format(prop_name) 99 | # Validate all properties on lists 100 | if type(getattr(o, prop_name)) == list: 101 | for i, v in enumerate(getattr(o, prop_name)): 102 | result = UtilInternal.is_invalid(v) 103 | if result: 104 | return "Property {}[{}] is invalid because {}".format(prop_name, i, result) 105 | 106 | # Recurse down to check validity of objects within objects 107 | result = UtilInternal.is_invalid(getattr(o, prop_name)) 108 | if result: 109 | return "Property {} is invalid because {}".format(prop_name, result) 110 | 111 | # Validate the property 112 | if "required" in validations and validations["required"] and getattr(o, prop_name) is None: 113 | return "Property {} is required, but was None".format(prop_name) 114 | if ( 115 | "minLength" in validations 116 | and getattr(o, prop_name) is not None 117 | and len(getattr(o, prop_name)) < validations["minLength"] 118 | ): 119 | return "Property {} must have a minimum length of {}, but found length of {}".format( 120 | prop_name, validations["minLength"], len(getattr(o, prop_name)) 121 | ) 122 | if ( 123 | "maxLength" in validations 124 | and getattr(o, prop_name) is not None 125 | and len(getattr(o, prop_name)) > validations["maxLength"] 126 | ): 127 | return "Property {} must have a maximum length of {}, but found length of {}".format( 128 | prop_name, validations["maxLength"], len(getattr(o, prop_name)) 129 | ) 130 | if ( 131 | "minItems" in validations 132 | and getattr(o, prop_name) is not None 133 | and len(getattr(o, prop_name)) < validations["minItems"] 134 | ): 135 | return "Property {} must have at least {} items, but found {}".format( 136 | prop_name, validations["minItems"], len(getattr(o, prop_name)) 137 | ) 138 | if ( 139 | "maxItems" in validations 140 | and getattr(o, prop_name) is not None 141 | and len(getattr(o, prop_name)) > validations["maxItems"] 142 | ): 143 | return "Property {} must have at most {} items, but found {}".format( 144 | prop_name, validations["maxItems"], len(getattr(o, prop_name)) 145 | ) 146 | if ( 147 | "maximum" in validations 148 | and getattr(o, prop_name) is not None 149 | and getattr(o, prop_name) > validations["maximum"] 150 | ): 151 | return "Property {} must be at most {}".format(prop_name, validations["maximum"]) 152 | if ( 153 | "minimum" in validations 154 | and getattr(o, prop_name) is not None 155 | and getattr(o, prop_name) < validations["minimum"] 156 | ): 157 | return "Property {} must be at least {}".format(prop_name, validations["minimum"]) 158 | if ( 159 | "pattern" in validations 160 | and getattr(o, prop_name) is not None 161 | and re.fullmatch(validations["pattern"], getattr(o, prop_name)) is None 162 | ): 163 | return "Property {} must match regex {}".format(prop_name, validations["pattern"]) 164 | 165 | for prop_name, types in o._types_map.items(): 166 | # Validate all properties with their respective types 167 | if "type" in types and getattr(o, prop_name) is not None: 168 | result = isinstance(getattr(o, prop_name), types["type"]) 169 | if not result: 170 | return "Property {} is invalid because it must be of type {}".format( 171 | prop_name, types["type"].__name__ 172 | ) 173 | if types["type"] == list and "subtype" in types: 174 | for i, v in enumerate(getattr(o, prop_name)): 175 | result = isinstance(v, types["subtype"]) 176 | if not result: 177 | return "Property {}[{}] is invalid because it must be of type {}".format( 178 | prop_name, i, types["subtype"].__name__ 179 | ) 180 | 181 | return False 182 | 183 | @staticmethod 184 | def raise_on_error_response(response): 185 | if response.status == ResponseStatusCode.Success: 186 | return 187 | elif response.status == ResponseStatusCode.InvalidRequest: 188 | raise InvalidRequestException(response.error_message, response.status, response.request_id) 189 | elif response.status == ResponseStatusCode.RequestPayloadTooLarge: 190 | raise RequestPayloadTooLargeException(response.error_message, response.status, response.request_id) 191 | elif response.status == ResponseStatusCode.ResourceNotFound: 192 | raise ResourceNotFoundException(response.error_message, response.status, response.request_id) 193 | elif response.status == ResponseStatusCode.ResponsePayloadTooLarge: 194 | raise ResponsePayloadTooLargeException(response.error_message, response.status, response.request_id) 195 | elif response.status == ResponseStatusCode.ServerTimeout: 196 | raise ServerTimeoutException(response.error_message, response.status, response.request_id) 197 | elif response.status == ResponseStatusCode.Unauthorized: 198 | raise UnauthorizedException(response.error_message, response.status, response.request_id) 199 | elif response.status == ResponseStatusCode.UnknownFailure: 200 | raise UnknownFailureException(response.error_message, response.status, response.request_id) 201 | elif response.status == ResponseStatusCode.NotEnoughMessages: 202 | raise NotEnoughMessagesException(response.error_message, response.status, response.request_id) 203 | elif response.status == ResponseStatusCode.MessageStoreReadError: 204 | raise MessageStoreReadErrorException(response.error_message, response.status, response.request_id) 205 | elif response.status == ResponseStatusCode.OutOfMemoryError: 206 | raise ServerOutOfMemoryException(response.error_message, response.status, response.request_id) 207 | elif response.status == ResponseStatusCode.UpdateFailed: 208 | raise UpdateFailedException(response.error_message, response.status, response.request_id) 209 | elif response.status == ResponseStatusCode.UpdateNotAllowed: 210 | raise UpdateNotAllowedException(response.error_message, response.status, response.request_id) 211 | elif response.status == ResponseStatusCode.UnknownOperation: 212 | raise UnknownOperationException(response.error_message, response.status, response.request_id) 213 | else: 214 | raise StreamManagerException( 215 | "Client is not able to understand this server response status code", "Unrecognized", response.request_id 216 | ) 217 | --------------------------------------------------------------------------------