Streaming OPC UA Data to Kinesis via SiteWise Edge Gateway
Bridging OPC UA telemetry to Kinesis Data Streams through SiteWise Edge Gateway and a custom Greengrass component.
SiteWise Edge Gateway can bridge OPC UA data sources to Kinesis Data Streams, making shop-floor telemetry available to downstream AWS services.

Setting Up the Backend
OPC UA Server
To create a dummy OPC UA server, use the opcua-asyncio Python library.
Install the required package:
pip install asyncuaDownload the example script (server-minimal.py) to your EC2 instance:
curl -OL https://raw.githubusercontent.com/FreeOpcUa/opcua-asyncio/master/examples/server-minimal.pyRun the script:
python server-minimal.pyGreengrass V2 Core Device
Set up a Greengrass V2 core device by following the official documentation. The installation procedure is outside the scope of this article.
After installation, perform the following:
- Deploy the
aws.greengrass.StreamManagercomponent. - Add the IAM policy below to the Token Exchange Role to allow data transmission to Kinesis Data Streams:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "kinesis:PutRecord", "kinesis:PutRecords" ], "Resource": "arn:aws:kinesis:*:$YOUR_AWS_ACCOUNT_ID:stream/$KINESIS_DATA_STREAM_NAME" } ]}SiteWise Edge Gateway
Set up a SiteWise Edge Gateway.
Choose Advanced setup.

The Data processing pack is not required.

Skip the Configure publisher step.

Specify the local endpoint of your OPC UA server and set the Greengrass stream name (e.g., SiteWise_Stream_Kinesis).



Review the configuration and click Create.

Kinesis Data Stream
Create a Kinesis Data Stream as the destination for your OPC UA data.

Kinesis Data Firehose
To persist the streamed data, configure a Kinesis Data Firehose delivery stream as follows:
- Source: The Kinesis Data Stream created above.
- Destination: An S3 bucket.

Creating a Greengrass Component
Create a custom Greengrass component to forward data from the Greengrass stream to Kinesis Data Streams. See the official documentation for details about component development.
Directory Structure
Organize the component’s files in the following structure:
- kinesis_data_stream.py- recipe.yaml- requirements.txt- stream_manager_sdk.zipImplementing the Component
The stream_manager_sdk.zip file should contain the necessary SDK for your Greengrass component. Refer to the AWS Greengrass Stream Manager SDK for Python for additional details and sample code.
Create requirements.txt. The stream-manager library provides access to Greengrass Stream Manager.
cbor2~=5.4.2stream-manager==1.1.1Create kinesis_data_stream.py with the following code. It uses the Greengrass Stream Manager SDK to forward data to a Kinesis Data Stream.
"""Script to use Greengrass Stream Manager to stream data to a Kinesis Data StreamSee also https://github.com/aws-greengrass/aws-greengrass-stream-manager-sdk-python/blob/main/samples/stream_manager_kinesis.py"""
import argparseimport asyncioimport loggingimport time
from stream_manager import ( ExportDefinition, KinesisConfig, MessageStreamDefinition, ReadMessagesOptions, ResourceNotFoundException, StrategyOnFull, StreamManagerClient,)
logging.basicConfig(level=logging.INFO)logger = logging.getLogger()
def main( stream_name: str, kinesis_stream_name: str, batch_size: int = None): try: # Create a client for the StreamManager client = StreamManagerClient()
# Try deleting the stream (if it exists) so that we have a fresh start try: client.delete_message_stream(stream_name=stream_name) except ResourceNotFoundException: pass
exports = ExportDefinition( kinesis=[KinesisConfig( identifier="KinesisExport" + stream_name, kinesis_stream_name=kinesis_stream_name, batch_size=batch_size, )] ) client.create_message_stream( MessageStreamDefinition( name=stream_name, strategy_on_full=StrategyOnFull.OverwriteOldestData, export_definition=exports ) )
while True: time.sleep(1)
except asyncio.TimeoutError: logger.exception("Timed out while executing") except Exception: logger.exception("Exception while running") finally: # Always close the client to avoid resource leaks if client: client.close()
def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser() parser.add_argument('--greengrass-stream', required=True, default='SiteWise_Stream_Kinesis') parser.add_argument('--kinesis-stream', required=True) parser.add_argument('--batch-size', required=False, type=int, default=500) return parser.parse_args()
if __name__ == '__main__': args = parse_args() logger.info(f'args: {args.__dict__}') main(args.greengrass_stream, args.kinesis_stream, args.batch_size)Create recipe.yaml with the following content. This example names the component jp.co.xyz.StreamManagerKinesis.
This recipe includes the following configurable parameters in ComponentConfiguration (lines 14-16):
- GreengrassStream: Name of the Greengrass stream
- KinesisStream: Kinesis Data Stream name to receive OPC UA data
- BatchSize: Batch size for data transfer (minimum: 1, maximum: 500)
# Replace $ArtifactsS3Bucket with your value to complete component registration.
RecipeFormatVersion: 2020-01-25
ComponentName: jp.co.xyz.StreamManagerKinesisComponentVersion: 1.0.0ComponentDescription: Streams data in Greengrass stream to a Kinesis Data Stream.ComponentPublisher: selfComponentDependencies: aws.greengrass.StreamManager: VersionRequirement: '^2.0.0'ComponentConfiguration: DefaultConfiguration: GreengrassStream: SiteWise_Stream_Kinesis KinesisStream: '' BatchSize: 100 # minimum 1, maximum 500
Manifests: - Platform: os: linux Lifecycle: Install: pip3 install --user -r {artifacts:decompressedPath}/component/requirements.txt Run: | export PYTHONPATH=$PYTHONPATH:{artifacts:decompressedPath}/stream_manager_sdk python3 {artifacts:decompressedPath}/component/kinesis_data_stream.py \ --greengrass-stream {configuration:/GreengrassStream} \ --kinesis-stream {configuration:/KinesisStream} \ --batch-size {configuration:/BatchSize} Artifacts: - URI: s3://$ArtifactsS3Bucket/artifacts/jp.co.xyz.StreamManagerKinesis/1.0.0/component.zip Unarchive: ZIPUploading Component Artifact
Archive the component files and upload them to your S3 bucket using the following commands:
S3_BUCKET=<YOUR_BUCKET_NAME>VERSION=1.0.0
zip component.zip kinesis_data_stream.py requirements.txtaws s3 cp component.zip s3://$S3_BUCKET/artifacts/jp.co.xyz.StreamManagerKinesis/$VERSION/rm component.zipRegistering Component
To register the component:
- Copy the contents of the
recipe.yamlfile created earlier. - Replace
$ArtifactsS3Bucketwith the actual S3 bucket name where the component artifact resides.

Deploying Component
Click Deploy.

Click Configure component.

Update the component’s configuration with the required details. Set the KinesisStream parameter to the Kinesis Data Stream name you created earlier.

Review the configuration and deploy the component.

Once the deployment is complete, the component will stream data from the Greengrass Stream to the specified Kinesis Data Stream.
Testing
The objects landing in the S3 bucket confirm the setup is working:
aws s3 cp s3://<YOUR_BUCKET_NAME>/... ./The example below is formatted for better readability.
{ "propertyAlias": "/MyObject/MyVariable", "propertyValues": [ { "value": { "doubleValue": 7.699999999999997 }, "timestamp": { "timeInSeconds": 1661581962, "offsetInNanos": 9000000 }, "quality": "GOOD" } ]}If the data appears as expected, the system is successfully streaming OPC UA data to the Kinesis Data Stream and persisting it in S3.
Conclusion
SiteWise Edge Gateway and a custom Greengrass component can forward telemetry from a sample OPC UA server to Kinesis Data Streams and persist it in S3.
SiteWise Edge Gateway polls the OPC UA server and writes the data to a named Greengrass stream such as SiteWise_Stream_Kinesis. Because it does not export directly to Kinesis, the custom component forwards those messages. StreamManagerClient and KinesisConfig from the Stream Manager SDK handle the transfer, while BatchSize—up to 500—controls how many messages are collected for each PutRecords call.
Plan to maintain the component’s IAM role, package, and versions as part of the pipeline rather than treating the component as a one-time setup task.
Related posts
Building and Deploying Greengrass Components in a Dockerized Environment
Develop AWS IoT Greengrass components locally using the Greengrass Core Docker image.
Configuring Record Separators for Kinesis Firehose in AWS IoT Core
Configure a record separator in an IoT Core topic rule's Firehose action so that records stored in S3 are separated by newlines.
Partitioning Kinesis Records with AWS IoT Payload Values
Use a customer ID from an IoT topic payload as the Kinesis partition key to preserve record order for each customer.
Streamlining NDJSON Processing with Kinesis Firehose Dynamic Partitioning
Use Kinesis Data Firehose dynamic partitioning to write NDJSON (Newline Delimited JSON) to S3 without a transformation Lambda function.
Querying S3 Logs with Athena and Kinesis Data Firehose
Deliver logs to S3 with Kinesis Data Firehose and query them in Athena, using custom prefixes to register partitions automatically.
