

# MQTT-enabled, V3 gateways for AWS IoT SiteWise Edge
<a name="mqtt-enabled-v3-gateway"></a>

AWS IoT SiteWise can use MQTT-enabled, V3 gateways, representing a significant advancement in the SiteWise Edge gateway architecture. This gateway type leverages the MQTT (Message Queuing Telemetry Transport) protocol for data communication, providing enhanced flexibility and efficiency in industrial IoT deployments.

The MQTT-enabled, V3 gateway uses MQTT for data transfer, enabling a lightweight, publish-subscribe network protocol that efficiently transports messages between devices and the cloud. You can set up various data destinations, including real-time data ingestion directly into AWS IoT SiteWise and buffered data ingestion using Amazon S3. To enable precise data collection, you can implement path filters to subscribe to specific MQTT topics.

MQTT-enabled, V3 gateways come with a pre-configured real-time destination with filters set to "\$1" (all topics), which you can customize or remove as needed. To streamline data management, only one real-time destination can exist in each gateway.

The MQTT-enabled architecture differs significantly from the Classic streams, V2 gateway. While V2 uses a stream-based approach, V3 employs MQTT, offering more configurable data destinations and filtering options. However, note that V3 does not support the data processing pack, which is available in V2.

The MQTT-enabled, V3 gateway offers several advantages: 
+ Improved scalability, due to MQTT's lightweight nature, enabling better handling of numerous devices and high-frequency data transmission.
+ Enhanced data control through path filters, enabling granular management of data collection and reducing unnecessary data transfer and processing.
+ Flexible data handling, allowing configuration between real-time processing and buffered storage based on specific needs.
+ Alignment with modern IoT communication standards, setting the stage for future enhancements and integrations.

Consider adopting the MQTT-enabled, V3 gateway for new deployments, especially when you require flexible data ingestion options and precise control over data collection.

**Note**  
For existing deployments or scenarios requiring the data processing pack, the Classic streams, V2 gateway remains a viable option.

By offering both gateway types, AWS IoT SiteWise ensures that you can choose the solution that best fits your specific industrial IoT needs, whether you prioritize advanced MQTT capabilities or compatibility with existing systems.

## Destinations and path filters
<a name="create-destination-summary"></a>

View the following topics to learn more about destinations and path filters in MQTT-enabled gateways:
+ [Understand AWS IoT SiteWise Edge destinations](gw-destinations.md#source-destination)
+ [Add an AWS IoT SiteWise Edge real-time destination](destinations-real-time.md)
+ [Add an AWS IoT SiteWise buffered destination using Amazon S3](destinations-buffered.md)
+ [Understand path filters for AWS IoT SiteWise Edge destinationsUnderstand path filters](gw-destinations.md#destinations-path-filters)
+ [Add path filters to AWS IoT SiteWise Edge destinations](destinations-add-path-filters.md)
+ [Manage AWS IoT SiteWise Edge destinations](destinations-manage.md)

# Connect external applications to the EMQX broker
<a name="connect-external-applications-emqx"></a>

This guide explains how to connect external applications to your AWS IoT SiteWise Edge gateway through an EMQX broker on your deployed MQTT-enabled, V3 gateway. External applications might include custom monitoring tools, third-party visualization software, or legacy systems that need to interact with your industrial data at the edge.

We'll cover the configuration steps for both Linux and Microsoft Windows environments, including EMQX deployment configuration, TLS setup for secure connections, and authorization rules to control access to specific topics.

**Note**  
EMQX is not a vendor or supplier for AWS IoT SiteWise Edge.

**Important**  
For securing connections to your gateway, we strongly recommend using certificate-based authentication through the AWS IoT Greengrass client device authentication feature. This method provides robust security through mutual TLS (mTLS) authentication. For more information, see [Connect client devices to core devices](https://docs.aws.amazon.com/greengrass/v2/developerguide/connect-client-devices.html) in the *AWS IoT Greengrass Version 2 Developer Guide*.

If you are not able to use certificate based authentication, follow this guide to setup authentication using usernames and passwords.

## Prerequisites
<a name="emqx-broker-prerequisites"></a>
+ A SiteWise Edge MQTT-enabled, V3 gateway that has been deployed and is online
+ Access to the gateway host
+ Access to the AWS IoT SiteWise and AWS IoT Greengrass consoles

**Topics**
+ [Prerequisites](#emqx-broker-prerequisites)
+ [Message payload format for the EMQX broker on AWS IoT SiteWise Edge](connect-broker-payload-format.md)
+ [Configure the EMQX broker](configure-emqx-broker.md)
+ [Connect an application to the EMQX broker on AWS IoT SiteWise Edge](connect-app-to-broker.md)
+ [Set up authorization rules for AWS IoT SiteWise Edge in EMQX](authorization-rules-emqx-broker.md)

# Message payload format for the EMQX broker on AWS IoT SiteWise Edge
<a name="connect-broker-payload-format"></a>

For the IoT SiteWise publisher component to consume data from your external application and publish it to the AWS IoT SiteWise cloud, the payload sent to the broker must meet specific requirements.

Understanding the payload format is key to successful MQTT communication with AWS IoT SiteWise Edge. While the connection setup process is covered in later sections, we present the payload requirements first to help you plan your implementation.

## MQTT topic requirements
<a name="connect-broker-mqtt-requirements"></a>

There are no restrictions on MQTT topic structure, including the number of levels or characters used. However, we recommend that the topic matches the `propertyAlias` field in the payload.

**Example property alias**  
If the MQTT topic is `site1/line1/compressor1/temperature`, ensure the `propertyAlias` matches.  

```
{
  "assetId": "compressor_asset_01",
  "propertyAlias": "site1/line1/compressor1/temperature",
  "propertyId": "temperature_sensor_01",
  "propertyValues": [
    {
      "quality": "GOOD",
      "timestamp": {
        "offsetInNanos": 0,
        "timeInSeconds": 1683000000
      },
      "value": {
        "doubleValue": 23.5
      }
    }
  ]
}
```

## JSON payload structure
<a name="connect-broker-json-payload"></a>

The MQTT message payload are written in JSON and follow the `PutAssetPropertyValueEntry` message format defined in the [AWS IoT SiteWise API Reference](https://docs.aws.amazon.com/iot-sitewise/latest/APIReference/API_PutAssetPropertyValueEntry.html).

```
{
   "assetId": "string",
   "propertyAlias": "string",
   "propertyId": "string",
   "propertyValues": [
      {
         "quality": "string",
         "timestamp": {
            "offsetInNanos": number,
            "timeInSeconds": number
         },
         "value": {
            "booleanValue": boolean,
            "doubleValue": number,
            "integerValue": number,
            "stringValue": "string"
         }
      }
   ]
}
```

**Note**  
For a message to be considered valid, only one of the following conditions can be true:  
The `propertyAlias` is set, or
Both `assetId` and `propertyId` are set
The `PutAssetPropertyValueEntry` has an `entryId` field that is not required in this context.

# Configure the EMQX broker
<a name="configure-emqx-broker"></a>

This section covers how to add usernames and passwords. It also covers how to establish a TLS connection from an external source using the added username and password. You can configure the EMQX broker using Linux or Microsoft Windows.

**Note**  
To configure the broker, you need a core device that is setup with the default EMQX configuration in your MQTT-enabled, V3 gateway.

**Important**  
After completing this procedure, we highly recommend configuring authorization rules. For more information, see [Set up authorization rules for AWS IoT SiteWise Edge in EMQX](authorization-rules-emqx-broker.md). Authorization rules for added users enhances security. 

## Update the EMQX deployment configuration for authentication
<a name="update-emqx-broker-authentication"></a>

**To update the EMQX deployment configuration for authentication**

1. <a name="sitewise-open-console"></a>Navigate to the [AWS IoT SiteWise console](https://console.aws.amazon.com/iotsitewise/).

1. In the left navigation, choose **Edge gateways** in the **Edge** section.

1. Choose the gateway to configure.

1. In the **Edge gateway configuration** section, copy your **Greengrass core device** value. Save it for later use.

1. Open the [AWS IoT console](https://console.aws.amazon.com/iot/).

1. On the left navigation, under the **Manage** section, choose **Greengrass devices**, then **Deployments**.

1. Find the core device value you saved earlier and choose that link to open the deployment.

1. Choose the **Actions** dropdown button, then **Revise**.

1. Read the message that appears and then choose **Revise deployment**. The **Specify target** page appears.

1. Choose **Next** until you reach the **Configure components** step.

1. Select the `aws.greengrass.clientdevices.mqtt.EMQX` radio button.

1. Choose the **Configure component** button. A configuration page appears for the component.

1. Under **Configuration update**, choose **Reset to default configuration for component version: 2.\$1.\$1**.

1. Enter the following configuration in the **Configuration to merge** section based on your OS.

------
#### [ Linux ]

   ```
   {
       "emqxConfig": {
           "authorization": {
               "no_match": "allow"
           },
           "listeners": {
               "tcp": {
                   "default": {
                       "enabled": true,
                       "enable_authn": false
                   }
               },
               "ssl": {
                   "default": {
                       "enabled": true,
                       "enable_authn": true,
                       "ssl_options": {
                           "verify": "verify_none",
                           "fail_if_no_peer_cert": false
                       }
                   }
               }
           },
           "authentication": {
               "enable": true,
               "backend": "built_in_database",
               "mechanism": "password_based",
               "password_hash_algorithm": {
                   "iterations": 210000,
                   "mac_fun": "sha512",
                   "name": "pbkdf2"
               },
               "user_id_type": "username"
           },
           "dashboard": {
               "listeners": {
                   "http": {
                       "bind": 18083
                   }
               }
           }
       },
       "authMode": "bypass",
       "dockerOptions": "-p 8883:8883 -p 127.0.0.1:1883:1883 -p 127.0.0.1:18083:18083 -v emqx-data:/opt/emqx/data -e EMQX_NODE__NAME=emqx@local",
       "requiresPrivilege": "true"
   }
   ```

------
#### [ Windows ]

   ```
   {
       "emqxConfig": {
           "authorization": {
               "no_match": "allow"
           },
           "listeners": {
               "tcp": {
                   "default": {
                       "enabled": true,
                       "enable_authn": false
                   }
               },
               "ssl": {
                   "default": {
                       "enabled": true,
                       "enable_authn": true,
                       "ssl_options": {
                           "verify": "verify_none",
                           "fail_if_no_peer_cert": false
                       }
                   }
               }
           },
           "authentication": {
               "enable": true,
               "backend": "built_in_database",
               "mechanism": "password_based",
               "password_hash_algorithm": {
                   "iterations": 210000,
                   "mac_fun": "sha512",
                   "name": "pbkdf2"
               },
               "user_id_type": "username"
           },
           "dashboard": {
               "listeners": {
                   "http": {
                       "bind": 18083
                   }
               }
           }
       },
       "authMode": "bypass",
       "requiresPrivilege": "true"
   }
   ```

   The `dockerOptions` field is only for Linux gateways.

------

1. Choose **Confirm**.

1. Choose **Next** until you reach the **Review** step.

1. Choose **Deploy**.

1. After the deployment succeeds, proceed to the next step.

## Enable username and password authentication
<a name="emqx-broker-username-password-auth"></a>

This section shows you how to add usernames and passwords through the EMQX dashboard GUI.

**Note**  
The EMQX-related instructions provided are for reference only. As EMQX documentation and features may change over time, and we do not maintain their documentation, we recommend consulting [EMQX's official documentation](https://docs.emqx.com/en/emqx/latest/) for the most current information.

------
#### [ EMQX Dashboard ]

**To enable username and password authentication through the EMQX dashboard**

1. Ensure that you are within the gateway host.

1. Open a browser window and visit [http://localhost:18083/](http://localhost:18083/).

1. Enter the default username of **admin** and the default password of **public**. For more information, see [EMQX Dashboard](https://docs.emqx.com/en/emqx/latest/dashboard/introduction.html#first-login) in the *EMQX Docs*.

1. After login, you are prompted to change your password. Update your password to continue to the EMQX Dashboard.

1. In the left navigation, choose the shield icon, then **Authentication**.

1. In the **Built-in Database** row, choose the **Users** button.

1. Choose the plus sign icon button to add users. An **Add** screen appears.

1. Enter a username and password for the user of the external application.

1. Choose **Save**. The username you chose appears in the **Authentication** page's table.

**Note**  
Existing or default authorization rules apply to the new user. It's recommended to review and adjust them to your external application needs.

------
#### [ EMQX Management with Linux ]

Use the AWS IoT SiteWise EMQX CLI tool at `/greengrass/v2/bin/swe-emqx-cli`.

**To enable username and password authentication through EMQX Management using Linux**

1. Change the admin password by running the following command:

   ```
   /greengrass/v2/bin/swe-emqx-cli admin change-pwd
   ```

1. When prompted, do the following:

   1. Enter your current administrator user (default is `admin`) and password (default is `public`).

   1. Enter and confirm your new password.

   If successful, you see the following message:

   ```
   admin password changed successfully
   ```

1. Add users for external applications by running the following command:

   ```
   /greengrass/v2/bin/swe-emqx-cli users add
   ```

1. When prompted, do the following:

   1. Enter the username for the new user.

   1. Enter and confirm the password for the new user.

   If successful, you see the following message:

   ```
   User '[username]' created successfully
   ```

1. Verify user configuration by running the following command:

   ```
   /greengrass/v2/bin/swe-emqx-cli users list
   ```

   The output shows all configured users:

   ```
   Users:
   - [your-added-username]
   
   Total users: 1
   ```

------
#### [ EMQX Management with Windows ]

Use the AWS IoT SiteWise EMQX CLI tool at one of the following locations:
+ PowerShell: `C:\greengrass\v2\bin\swe-emqx-cli.ps1`
+ Command Prompt: `C:\greengrass\v2\bin\swe-emqx-cli.bat`

**To enable username and password authentication through EMQX Management using Windows**

1. Change the admin password by running the following command:

   ```
   C:\greengrass\v2\bin\swe-emqx-cli.ps1 admin change-pwd
   ```

1. When prompted, do the following:

   1. Enter your current administrator user (default is `admin`) and password (default is `public`).

   1. Enter and confirm your new password.

   If successful, you see the following message:

   ```
   admin password changed successfully
   ```

1. Add users for external applications by running the following command:

   ```
   C:\greengrass\v2\bin\swe-emqx-cli.ps1 users add
   ```

1. When prompted, do the following:

   1. Enter the username for the new user.

   1. Enter and confirm the password for the new user.

   If successful, you see the following message:

   ```
   User '[username]' created successfully
   ```

1. Verify user configuration by running the following command:

   ```
   C:\greengrass\v2\bin\swe-emqx-cli.ps1 users list
   ```

   The output shows all configured users:

   ```
   Users:
   - [your-added-username]
   
   Total users: 1
   ```

------

# Connect an application to the EMQX broker on AWS IoT SiteWise Edge
<a name="connect-app-to-broker"></a>

The EMQX broker uses Transport Layer Security (TLS) on port 8883 to encrypt all communications, ensuring your data remains protected during transmission. This section walks you through the steps to establish connections between your applications and the EMQX broker. Following these steps helps maintain the integrity and confidentiality of your industrial data. The connection process involves two main approaches: using automated IP discovery through components, or manually configuring DNS names and IP addresses as Subject Alternative Names (SANs) in your TLS certificates. Each method has its own advantages depending on your network setup and security requirements. This documentation will guide you through both options.

**Topics**
+ [Configure TLS for secure connections to the EMQX broker on AWS IoT SiteWise Edge](#configure-tls-emqx-broker)
+ [Test the EMQX broker connection on AWS IoT SiteWise Edge](#test-emqx-connection)
+ [Use your own CA](#configure-tls-custom-ca)
+ [Open port 8883 for external firewall connections](#emqx-firewall)

## Configure TLS for secure connections to the EMQX broker on AWS IoT SiteWise Edge
<a name="configure-tls-emqx-broker"></a>

By default, AWS IoT Greengrass generates a TLS server certificate for the EMQX broker that is signed by the core device certificate authority (CA). For more information, see [Connecting client devices to an AWS IoT Greengrass Core device with an MQTT broker](https://docs.aws.amazon.com/greengrass/v2/developerguide/connecting-to-mqtt.html).

### Retrieve the TLS certificate
<a name="configure-tls-retrieve-certificate"></a>

To get the CA certificate run the following command on the gateway host:

------
#### [ Linux ]

Run the following command in a shell session on the gateway host:

```
/greengrass/v2/bin/swe-emqx-cli cert
```

This command displays the certificate location and prints the certificate's content.

You can alternatively save the certificate to a file using this command:

```
/greengrass/v2/bin/swe-emqx-cli cert --output /path/to/certificate.pem
```

------
#### [ Windows ]

Run the following command in a PowerShell session on the gateway host:

```
C:\greengrass\v2\bin\swe-emqx-cli.ps1 cert
```

This command displays the certificate location and prints the certificate's content.

You can alternatively save the certificate to a file using this command:

```
C:\greengrass\v2\bin\swe-emqx-cli.ps1 cert --output C:\path\to\certificate.pem
```

The CLI automatically locates the certificate regardless of the exact path on your system.

------

Copy the contents of the ca.pem file to the external application that you're connecting to the broker. Save it as `BrokerCoreDeviceCA.pem`.

### Add custom DNS names/IP addresses to the TLS server certificate
<a name="configure-tls-custom-dns-ip"></a>

The subject alternative name (SAN) on the cert generated by AWS IoT Greengrass is `localhost`. When establishing a TLS connection from outside of the gateway host, the TLS verification step fails because the broker’s hostname does not match the hostname of `localhost` on the server certificate.

To address mismatched hostname issue, AWS IoT Greengrass provides two ways of managing core device endpoints. This section covers both options. For more detailed information, see [Manage core device endpoints](https://docs.aws.amazon.com/greengrass/v2/developerguide/manage-core-device-endpoints.html) in the *AWS IoT Greengrass Version 2 Developer Guide*.
+ To connect to the EMQX broker using the core device's IP address, use the Automated IP discovery section.
+ To connect to the EMQX broker using a DNS name instead of IP address, you use the Manual management section.

------
#### [ Automated IP discovery ]

This option allows your core device to automatically discover its IP address and add it as a Subject Alternative Name (SAN) to the broker certificate.

1. Add the `aws.greengrass.clientdevices.IPDetector` component to your core device’s deployment.

1. Deploy the changes to your device

1. Wait for deployment to complete.

   After the deployment completes, you can establish a secure TLS connection using the broker's IP address.

   The IP address is automatically added as a SAN to the broker certificate.

------
#### [ Manual DNS and IP Configuration ]

You can manually add DNS names and IP addresses as Subject Alternative Names (SANs) to your TLS certificate. This method is useful when you have configured a DNS name for your gateway host.

**Important**  
If you are using the IPDetector component, remove it from your deployment before proceeding. The IPDetector component overrides manual endpoint configurations.

**To manually configure endpoints**

1. <a name="sitewise-open-console"></a>Navigate to the [AWS IoT SiteWise console](https://console.aws.amazon.com/iotsitewise/).

1. In the left navigation, choose **Edge gateways** in the **Edge** section.

1. Choose the gateway to configure.

1. In the **Edge gateway configuration** section, choose your **Greengrass core device** url. The core device's page appears.

1. Choose the **Client devices** tab.

1. Choose **Manage endpoints**.

1. In the Manage endpoints dialog box, enter the DNS name(s) and any IP addresses you want to add as SANs. Use port 8883.

1. Choose **Update**.

The broker's TLS server certificate updates automatically to include your new endpoints.

**To verify the TLS server certificate update using Linux**

1. Start a shell session on your gateway host.

   ```
   docker exec emqx openssl x509 -in ./data/cert.pem -text -noout | grep -A1 "Subject Alternative Name"
   ```

1. The command returns an output similar to the following:

   ```
   X509v3 Subject Alternative Name: 
   DNS:endpoint_you_added, DNS:localhost
   ```

1. Verify that your endpoint appears in the list of SANs.

**To verify the TLS server certificate update using Windows**

1. Start a shell session on your gateway host.

   ```
   (Get-PfxCertificate -FilePath "C:\greengrass\v2\work\aws.greengrass.clientdevices.mqtt.EMQX\v2\data\cert.pem").Extensions | Where-Object { $_.Oid.FriendlyName -eq "Subject Alternative Name" } | ForEach-Object { "Subject Alternative Name:", ($_.Format($true) -split "`n")[0..1] }
   ```

1. The command returns an output similar to the following:

   ```
   Subject Alternative Name:
   DNS Name=your-endpoint
   DNS Name=localhost
   ```

1. Verify that the endpoint you added is in the list of SANs.

------

## Test the EMQX broker connection on AWS IoT SiteWise Edge
<a name="test-emqx-connection"></a>

After configuring your EMQX broker with TLS certificates and authentication credentials, it's important to verify that your setup works correctly. Testing the connection helps ensure that your security configurations are properly implemented and that clients can successfully establish encrypted connections to the broker. This section demonstrates how to test your broker connection using the Mosquitto command line interface (CLI) client, a widely-used MQTT client tool that supports TLS encryption and authentication.

### Use Mosquitto CLI client to test the EMQX broker connection
<a name="test-emqx-connection-mosquitto"></a>

In this step we will use the mosquitto CLI client to test our setup and make sure we can connect successfully to the broker using the username and password we created earlier. To get the `BrokerCoreDeviceCA.pem` follow steps under Step 3: Setting up TLS.

```
mosquitto_sub -h hostname|ip address \
    -p 8883 \
    -t "#" \
    -q 1 \
    -u username -P password \
    --cafile BrokerCoreDeviceCA.pem
```

**Note**  
You may get an SSL:verify error if the hostname/IP address you are connecting to does not match the Subject Alternative Name (SAN) that is on the CA cert you're passing to the client. See "Adding custom DNS names/IP addresses to the TLS server cert" under Step 3: Setting up TLS for how to get a certificate with the correct SAN.

At this point, all users have access to publish and subscribe to all topics on the broker. Proceed to [Set up authorization rules for AWS IoT SiteWise Edge in EMQX](authorization-rules-emqx-broker.md).

## Use your own CA
<a name="configure-tls-custom-ca"></a>

AWS IoT Greengrass outlines how to configure your own client device auth component to use your own certificate authority (CA). The client device auth component (`aws.greengrass.clientdevices.Auth`) authenticates client devices and authorizes client device actions. For more information, see [Using your own certificate authority](https://docs.aws.amazon.com/greengrass/v2/developerguide/connecting-to-mqtt.html#use-your-own-CA) in the *AWS IoT Greengrass Version 2 Developer Guide*.

To use your own CA, add the `aws.greengrass.clientdevices.Auth` component to your deployment so that you can specify a custom configuration.

## Open port 8883 for external firewall connections
<a name="emqx-firewall"></a>

------
#### [ Linux ]

In your Linux host firewall rule, add an inbound rule for port 8883 to allow incoming connections from outside of the gateway host. If there are any firewalls in place, ensure that incoming TLS connections on port 8883 are allowed.

------
#### [ Windows ]

In your Microsoft Windows host firewall rule, add an inbound rule for port 8883 to allow incoming connections from outside of the gateway host. Ensure the rule is an allow rule, of type port, specifying port 8883. You can configure this according to your network configuration to allow connections from your external applications to the broker.

------

# Set up authorization rules for AWS IoT SiteWise Edge in EMQX
<a name="authorization-rules-emqx-broker"></a>

EMQX supports adding authorization rules based on identifiers such as username, IP address or client ID. This is useful if you want to limit the number of external applications connecting to various operations or topics.

**Topics**
+ [Configure authorization using the built-in database with Linux](add-auth-rules-database-emqx-broker-linux.md)
+ [Configure authorization using the built-in database with Windows](add-auth-rules-database-emqx-broker-windows.md)
+ [Update the EMQX deployment configuration for authorization](update-emqx-broker-authorization.md)
+ [Add authorization rules through the EMQX Dashboard for users](add-rules-emqx-broker.md)

# Configure authorization using the built-in database with Linux
<a name="add-auth-rules-database-emqx-broker-linux"></a>

When you configure authorization rules, there are two configuration choices that depend on your deployment setup.
+ **Docker** – If you're running a standard Docker installation without Litmus Edge, use the **Docker bridge gateway** configuration. This is typically the case when you've only deployed AWS IoT SiteWise components.
+ **Litmus Edge** – If you have Litmus Edge installed on your gateway, use the **Litmus Edge network subnet** configuration.

**Note**  
If you initially configure the Docker bridge gateway and later install Litmus Edge, reconfigure the authorization rules using the Litmus Edge network subnet option to ensure proper communication between all components.

**To add basic authorization rules**

1. Verify that the EMQX broker is deployed and running.

1. Start a shell session on your gateway host.

------
#### [ Docker without Litmus Edge ]

   For standard Docker installation without Litmus Edge, run:

   ```
   /greengrass/v2/bin/swe-emqx-cli acl init
   ```

------
#### [ Litmus Edge network subnet ]

   If you're using Litmus Edge, determine the Litmus Edge network subnet IP:

   ```
   docker network inspect LitmusNetwork | grep IPAM -A9
   ```

   Note the Subnet value from the output and run the following command. Replace `litmus_subnet_ip` with the Subnet value from the previous step.

   ```
   /greengrass/v2/bin/swe-emqx-cli acl init litmus_subnet_ip
   ```

------

   The tool automatically creates and applies authorization rules to allow connections from the provided IP address to the broker. It allows access to all topics. This includes the IoT SiteWise OPC UA collector and IoT SiteWise publisher.

1. Proceed to [Update the EMQX deployment configuration for authorization](update-emqx-broker-authorization.md).

# Configure authorization using the built-in database with Windows
<a name="add-auth-rules-database-emqx-broker-windows"></a>

This section covers configuring authorization rules using the built-in database for Windows deployments.

**To add basic authorization rules**

1. Verify that the EMQX broker is deployed and running.

1. Run the AWS IoT SiteWise EMQX CLI tool: 

   ```
   C:\greengrass\v2\bin\swe-emqx-cli.ps1 acl init
   ```

   The tool automatically creates and applies ACL rules allowing connections from localhost (127.0.0.1) to the broker. It allows access to all topics. This includes the IoT SiteWise OPC UA collector and IoT SiteWise publisher.

1. Proceed to [Update the EMQX deployment configuration for authorization](update-emqx-broker-authorization.md).

# Update the EMQX deployment configuration for authorization
<a name="update-emqx-broker-authorization"></a>

**To update the EMQX deployment configuration for authorization**

1. <a name="sitewise-open-console"></a>Navigate to the [AWS IoT SiteWise console](https://console.aws.amazon.com/iotsitewise/).

1. In the left navigation, choose **Edge gateways** in the **Edge** section.

1. Choose the gateway to configure.

1. In the **Edge gateway configuration** section, copy your **Greengrass core device** value. Save it for later use.

1. Open the [AWS IoT console](https://console.aws.amazon.com/iot/).

1. On the left navigation, under the **Manage** section, choose **Greengrass devices**, then **Deployments**.

1. Find the core device value you saved earlier and choose that link to open the deployment.

1. Choose the **Actions** dropdown button, then **Revise**.

1. Read the message that appears and then choose **Revise deployment**. The **Specify target** page appears.

1. Choose **Next** until you reach the **Configure components** step.

1. Select the `aws.greengrass.clientdevices.mqtt.EMQX` radio button.

1. Choose the **Configure component** button. A configuration page appears for the component.

1. Under **Configuration update**, choose **Reset to default configuration for component version: 2.\$1.\$1**.

1. Paste the following content in the **Configuration to merge** section based on your OS.

------
#### [ Linux ]

   ```
   {
       "emqxConfig": {
           "authorization": {
               "no_match": "deny",
               "sources": [
                   {
                       "type": "built_in_database"
                   },
                   {
                       "type": "file",
                       "path": "data/authz/acl.conf"
                   }
               ]
           },
           "listeners": {
               "tcp": {
                   "default": {
                       "enabled": true,
                       "enable_authn": false
                   }
               },
               "ssl": {
                   "default": {
                       "enabled": true,
                       "enable_authn": true,
                       "ssl_options": {
                           "verify": "verify_none",
                           "fail_if_no_peer_cert": false
                       }
                   }
               }
           },
           "authentication": {
               "enable": true,
               "backend": "built_in_database",
               "mechanism": "password_based",
               "password_hash_algorithm": {
                   "iterations": 210000,
                   "mac_fun": "sha512",
                   "name": "pbkdf2"
               },
               "user_id_type": "username"
           },
           "dashboard": {
               "listeners": {
                   "http": {
                       "bind": 18083
                   }
               }
           }
       },
       "authMode": "bypass",
       "dockerOptions": "-p 8883:8883 -p 127.0.0.1:1883:1883 -p 127.0.0.1:18083:18083 -v emqx-data:/opt/emqx/data -e EMQX_NODE__NAME=emqx@local",
       "requiresPrivilege": "true"
   }
   ```

------
#### [ Windows ]

   ```
   {
       "emqxConfig": {
           "authorization": {
               "no_match": "deny",
               "sources": [
                   {
                       "type": "built_in_database"
                   },
                   {
                       "type": "file",
                       "path": "C:\\greengrass\\v2\\work\\aws.greengrass.clientdevices.mqtt.EMQX\\v2\\data\\authz\\acl.conf"
                   }
               ]
           },
           "listeners": {
               "tcp": {
                   "default": {
                       "enabled": true,
                       "enable_authn": false
                   }
               },
               "ssl": {
                   "default": {
                       "enabled": true,
                       "enable_authn": true,
                       "ssl_options": {
                           "verify": "verify_none",
                           "fail_if_no_peer_cert": false
                       }
                   }
               }
           },
           "authentication": {
               "enable": true,
               "backend": "built_in_database",
               "mechanism": "password_based",
               "password_hash_algorithm": {
                   "iterations": 210000,
                   "mac_fun": "sha512",
                   "name": "pbkdf2"
               },
               "user_id_type": "username"
           },
           "dashboard": {
               "listeners": {
                   "http": {
                       "bind": 18083
                   }
               }
           }
       },
       "authMode": "bypass",
       "requiresPrivilege": "true"
   }
   ```

------

1. Choose **Confirm**.

1. Choose **Next** until you reach the **Review** step.

1. Choose **Deploy**.

**Note**  
From this point onward, you can't edit the ACL file to update the authorization rules. Alternatively, you can proceed to [Add authorization rules through the EMQX Dashboard for users](add-rules-emqx-broker.md) after a successful deployment.

# Add authorization rules through the EMQX Dashboard for users
<a name="add-rules-emqx-broker"></a>

You can add or update authorization rules using the EMQX Dashboard or the AWS IoT SiteWise EMQX CLI tool. The AWS IoT SiteWise EMQX CLI tool manages authorization using EMQX's built-in database.

**Note**  
Adding authorization rules is an advanced configuration step that requires understanding of MQTT topic patterns and access control. For more information about creating authorization rules using EMQX's built-in database, see [Use Built-in Database](https://docs.emqx.com/en/emqx/latest/access-control/authz/mnesia.html) in the *EMQX Docs*.

**Note**  
The EMQX-related instructions provided are for reference only. As EMQX documentation and features may change over time, and we do not maintain their documentation, we recommend consulting [EMQX's official documentation](https://docs.emqx.com/en/emqx/latest/) for the most current information.

------
#### [ EMQX dashboard ]

This procedure shows how you can add authorization rules on the EMQX dashboard.

The EMQX dashboard is only accessible from within the gateway host. If you try to connect from outside of the gateway host, you can't access the dashboard.

**To add authorization rules using the EMQX Dashboard**

1. Ensure that you are within the gateway host.

1. Open a browser window and visit [http://localhost:18083/](http://localhost:18083/).

1. Login to the the EMQX dashboard. This procedure assumes that you've changed your default login credentials to something of your choosing. For more information on intial setup, see [Enable username and password authentication](configure-emqx-broker.md#emqx-broker-username-password-auth).

1. Choose the shield icon, then **Authorization** from the dropdown menu.

1. Choose the **Permissions** button on the **Built-in Database** row. 

1. In the Built-in Database authorization section, add or update the user authorization rules for your business needs. For more guidance on creating rules, see the [Use Built-in Database](https://docs.emqx.com/en/emqx/latest/access-control/authz/mnesia.html) section in the *EMQX Docs*.

------
#### [ AWS IoT SiteWise CLI tool using Linux ]

**To manage authorization rules using the AWS IoT SiteWise EMQX CLI tool in Linux:**
+ Add authorization rules for a user using the following format:

  ```
  /greengrass/v2/bin/swe-emqx-cli auth add your-username your-action your-permission your-topic [your-action-permission-topic]
  ```

**Example Add authorization rules for a user**  
This example shows how to add rules for a user named `system1`:  

```
/greengrass/v2/bin/swe-emqx-cli auth add system1 \
    publish allow "sensors/#" \
    subscribe allow "control/#" \
    all deny "#"
```

**Example : View authorization rules for a user**  
To view authorization rules for the `system1` users, run the following command:  

```
/greengrass/v2/bin/swe-emqx-cli auth list system1
```

**Example : View all existing authorization rules**  
To view all of the authorization rules you currently have, run the following command:  

```
/greengrass/v2/bin/swe-emqx-cli auth list
```

**Example : Delete all authorization rules for a user**  
To delete all of the authorization rules applied to a particular user, run the following command:  

```
/greengrass/v2/bin/swe-emqx-cli auth delete system1
```
You are prompted to confirm the deletion.

------
#### [ AWS IoT SiteWise CLI tool using Windows ]

**To manage authorization rules using the AWS IoT SiteWise EMQX CLI tool in Windows PowerShell:**
+ Add authorization rules for a user using the following format:

  ```
  C:\greengrass\v2\bin\swe-emqx-cli.ps1 auth add your-username your-action your-permission your-topic [your-action-permission-topic]
  ```

**Example : Add authorization rules for a user**  
This example shows how to add rules for a user named `system1`:  

```
C:\greengrass\v2\bin\swe-emqx-cli.ps1 auth add system1 `
    publish allow "sensors/#" `
    subscribe allow "control/#" `
    all deny "#"
```

**Example : View authorization rules for a user**  
To view authorization rules for the `system1` users, run the following command:  

```
C:\greengrass\v2\bin\swe-emqx-cli.ps1 auth list system1
```

**Example : View all existing authorization rules**  
To view all of the authorization rules you currently have, run the following command:  

```
C:\greengrass\v2\bin\swe-emqx-cli.ps1 auth list
```

**Example : Delete all authorization rules for a user**  
To delete all of the authorization rules applied to a particular user, run the following command:  

```
C:\greengrass\v2\bin\swe-emqx-cli.ps1 auth delete system1
```
You are prompted to confirm the deletion.

------

# Process and visualize data with SiteWise Edge and open-source tools
<a name="open-source-edge-integrations"></a>

Configure AWS IoT SiteWise Edge MQTT-enabled gateways with open-source tools for local processing and visualization to enhance your industrial data management capabilities.

With SiteWise Edge, you can create a local data processing pipeline using external, open-source tools. Use [Node-RED®](https://nodered.org/) to store time-series data with [InfluxDB®](https://www.influxdata.com/lp/influxdb-database/), and monitor operations through [Grafana®](https://grafana.com/) dashboards.

Node-RED processes and transforms your data flows, while InfluxDB provides time-series data storage. Grafana displays your real-time operational data. Use these tools with SiteWise Edge to synchronize data between your local environment and the AWS Cloud, giving you both immediate local insights and long-term cloud-based analytics capabilities.

**Note**  
Node-RED®, InfluxDB®, and Grafana® are not vendors or suppliers for SiteWise Edge.

![\[A diagram that shows a few data sources and the turbine simulator connecting to the EMQX Broker to publish. Then the EMQX broker subscribes to the AWS IoT SiteWise Gateway and Node-RED. Node-RED feeds into InfluxDB, and then Influx DB into the Grafana Dashboard.\]](http://docs.aws.amazon.com/iot-sitewise/latest/userguide/images/gateway-open-source-overview.png)


**Note**  
In this guide, we're using the open-source version of [Grafana](https://grafana.com/) for SiteWise Edge as opposed to the [Amazon Managed Grafana](https://docs.aws.amazon.com/grafana/latest/userguide/what-is-Amazon-Managed-Service-Grafana.html) service.

## Deployment options
<a name="deployment-options"></a>

You can deploy this solution using one of two approaches. With a Microsoft Windows manual setup, you control component configuration and integration with your infrastructure. With Linux, you can use Docker to deploy pre-configured components in containers.

Choose the method that meets your operational requirements.
+ [Set up open source integrations manually (Windows)](windows-manual-setup.md) – For custom configurations or existing infrastructure
+ [Set up open-source integrations with Docker (Linux)](linux-docker-setup.md) – For rapid deployment with pre-configured components

## Wind farm example overview
<a name="open-source-example-overview"></a>

This guide uses a wind farm example to demonstrate how you can monitor wind speed for a turbine on a wind farm. This practical scenario illustrates common industrial monitoring needs where both local and cloud-based visibility are valuable for operational efficiency.

With this integration, you can:
+ Collect data from industrial equipment using an AWS IoT SiteWise Edge gateway
+ Process data locally with Node-RED, InfluxDB, and Grafana
+ Store data locally using InfluxDB
+ Monitor data in real time using Grafana dashboards

Throughout this guide, we use the example of a windfarm. We use Node-RED to simulate a turbine that generates wind speed data. Node-RED translates the data payload, publishes the data to the SiteWise Edge MQTT broker, subscribes to receive data from the broker, and stores the data locally in InfluxDB. This approach ensures that all of the operational data is available both locally for immediate access and in the cloud for further analytics. By implementing this pattern, you gain resilience against network disruptions while maintaining the ability to perform advanced analytics in the AWS Cloud. Grafana connects to InfluxDB for local monitoring, providing operators with real-time visibility into metrics without cloud dependencies. A SiteWise Edge MQTT-enabled gateway connects to the same MQTT broker to send data to AWS IoT SiteWise, creating a bridge between your edge operations and cloud-based services.

You can use your own data and configurations to create a similar workflow tailored to your specific industrial requirements, whether you're monitoring manufacturing equipment, utility infrastructure, or other industrial assets.

## Requirements for open-source integrations
<a name="open-source-requirements"></a>

Before implementing open-source integrations with SiteWise Edge, ensure your environment meets the necessary requirements.
+ **Hardware requirements** - Your gateway hardware must meet the requirements for SiteWise Edge gateways. For more information, see [AWS IoT SiteWise Edge self-hosted gateway requirements](configure-gateway-ggv2.md) for MQTT-enabled, V3 gateways and [Requirements for the AWS IoT SiteWise Edge application](siemens-app-gateway-requirements.md).
**Important**  
When deploying additional open-source components, ensure your hardware meets the requirements for [InfluxDB](https://docs.influxdata.com/influxdb/v2/install/), [Node-RED](https://nodered.org/docs/getting-started/), and [Grafana](https://grafana.com/docs/grafana/latest/setup-grafana/installation/).
+ Your network configuration must support both local communication between components and cloud connectivity for SiteWise Edge.
+ All services must run on the same host.

## Security considerations
<a name="open-source-security-considerations"></a>

We recommend that you encrypt all communications between components, especially when accessing interfaces from non-local networks. Implement proper access controls for each component and follow AWS best practices for AWS IoT SiteWise Edge gateway configuration and AWS account security.

**Development environment**  
This guide demonstrates Node-RED, InfluxDB, and Grafana running and accessed locally on a gateway host. For production deployments that require external access, implement security measures including TLS encryption, authentication, and authorization. Follow each application's security best practices.

**Third-party software**  
This solution uses third-party software not maintained by AWS, including InfluxDB, Node-RED, Grafana, and the `node-red-contrib-influxdb` plugin. Before deployment, ensure these components comply with your organization's security requirements, compliance standards, and governance policies.

**Important**  
This guide references and uses third-party software not owned or maintained by AWS. Before implementation, ensure that all components meet your security, compliance, and governance requirements. Keep all software updated with the latest security patches and follow best practices for securing your edge deployment.  
 InfluxDB, Node-RED, Grafana are not vendors or suppliers for SiteWise Edge.

## Other considerations
<a name="open-source-other-considerations"></a>

Consider these additional factors when implementing open-source integrations with SiteWise Edge.
+ Use the latest versions of all services, tools, and components.
+ Filter and aggregate data locally before cloud transmission to reduce AWS IoT SiteWise data ingestion costs. Configure appropriate data retention periods in InfluxDB and properly size your gateway hardware. For more information, see [AWS IoT SiteWise pricing](https://aws.amazon.com/iot-sitewise/pricing/).
+ Implement regular backup procedures for all data.
+ Monitor resource usage on your gateway and configure appropriate resource limits for each component. Implement data retention policies in InfluxDB to manage disk usage.

# Set up open source integrations manually (Windows)
<a name="windows-manual-setup"></a>

Use this guide to manually create a time series bucket for wind speed data that connects with Grafana® and Node-RED®.

 Manually install and configure Node-RED, InfluxDB®, and Grafana on Microsoft Windows to control your deployment configuration. You can store and manage time series data from your devices using InfluxDB.

## Manual setup prerequisites
<a name="windows-open-source-prerequisites"></a>

Before you begin, complete these requirements:

**Note**  
Run all services (SiteWise Edge, InfluxDB, Node-RED, and Grafana) on the same host.
+ Install an MQTT-enabled, V3 gateway. For more information, see [MQTT-enabled, V3 gateways for AWS IoT SiteWise Edge](mqtt-enabled-v3-gateway.md).
+ Install and run these services locally:
  + InfluxDB OSS v2. For installation steps, see [Install InfluxDB](https://docs.influxdata.com/influxdb/v2/install/).
  + Node-RED. For installation steps, see [Install Node-RED locally](https://nodered.org/docs/getting-started/local).
  + Grafana. For installation steps, see [Install Grafana](https://grafana.com/docs/grafana/latest/setup-grafana/installation/).

# Set up local storage with InfluxDB
<a name="windows-influxdb-setup"></a>

With InfluxDB®, you can store time series data from your devices locally. The purpose of local storage capability is to maintain operational visibility during network disruptions and reduce latency for time-critical applications. You can perform analysis and visualization at the edge while still having the option to selectively forward data to the cloud.

In this section, you create a time series bucket for turbine wind speed data and generate an API token for Grafana® and Node-RED® connectivity. The InfluxDB bucket serves as a dedicated storage container for your time series data, similar to a database in traditional systems. The API token enables secure programmatic access to your data.

**To set up InfluxDB**

1. After completing the prerequisite steps and ensuring all tools are running on the same host, open your web browser and go to [http://127.0.0.1:8086](http://127.0.0.1:8086).

1. (Optional) Enable TLS encryption for enhanced security. For more information, see [Enable TLS encryption](https://docs.influxdata.com/influxdb/v2/admin/security/enable-tls/) in the *InfluxData Documentation*.

1. Create a time series InfluxDB bucket to store data from Node-RED. The bucket will serve as a dedicated container for your wind farm data, allowing you to organize and manage retention policies specific to this dataset. For more information, see [Manage buckets](https://docs.influxdata.com/influxdb/v2/admin/buckets/) in the *InfluxData Documentation*.

1. (Optional) Configure the data retention period for your edge location. Setting appropriate retention periods helps manage storage resources efficiently by automatically removing older data that's no longer needed for local operations.

   For information about data retention, see [Data retention in InfluxDB](https://docs.influxdata.com/influxdb/v2/reference/internals/data-retention/) in the *InfluxData Documentation*.

1. Generate an API token for the bucket. This token will enable secure communication between InfluxDB and other components like Node-RED and Grafana. This way, only authorized services can read from or write to your data store. For more information, see [Create a token](https://docs.influxdata.com/influxdb/cloud/admin/tokens/create-token/) in the *InfluxData Documentation*.

After you complete these steps, you can store time series data in your InfluxDB instance, providing a foundation for local data persistence and analysis in your edge environment.

# Configure Node-RED flows for AWS IoT SiteWise data integration
<a name="windows-nodered-config"></a>

With Node-RED®, you can implement two flows to manage data between your devices and AWS IoT SiteWise. These flows work together to create a comprehensive data management solution that addresses both local and cloud data flow.
+ **Data publish flow** – Publishes to the cloud. The data publish flow sends data to AWS IoT SiteWise. This flow simulates a turbine device by generating sensor data, translating it to AWS IoT SiteWise format, and publishing to the SiteWise Edge MQTT broker. This enables you to leverage AWS IoT SiteWise's cloud capabilities for storage, analytics, and integration with other AWS services.

  For more information, see [Configure the data publish flow](windows-nodered-data-publish-flow.md).
+ **Data retention flow** – Stores data at the edge. The data retention flow subscribes to the SiteWise Edge MQTT broker to receive data, translate it into InfluxDB® format, and stores it locally for monitoring. This local storage provides immediate access to operational data, reduces latency for time-critical applications, and ensures continuity during network disruptions.

  For more information, see [Configure the data retention flow](windows-nodered-data-retention-flow.md).

These two flows work together to ensure data is both sent to AWS IoT SiteWise and stored locally for immediate access.

To access your Node-RED console, go to [http://127.0.0.1:1880](http://127.0.0.1:1880). For information about enabling TLS, see [Enable TLS encryption](https://docs.influxdata.com/influxdb/v2/admin/security/enable-tls/).

# Configure the data publish flow
<a name="windows-nodered-data-publish-flow"></a>

The data publish flow uses three nodes to create a pipeline that sends your industrial data to the cloud. This flow is essential for enabling cloud-based analytics, long-term storage, and integration with other AWS services. First, simulated device data is sent to the SiteWise Edge MQTT broker. The gateway picks up the data from the broker which allows for transmission to the AWS IoT SiteWise cloud, where you can leverage powerful analytics and visualization capabilities.
+ **Data input** - Receives device data from your industrial equipment or simulators
+ **Data translator for AWS IoT SiteWise** - Translates data to AWS IoT SiteWise format to ensure compatibility with the SiteWise Edge gateway
+ **MQTT publisher** - Publishes data to SiteWise Edge MQTT broker, making it available to both local and cloud consumers

![\[A diagram showing the Node-RED data publishing flow. It sends simulated device data to the SiteWise Edge MQTT broker for pickup by SiteWise Edge Gateway and then onto the AWS IoT SiteWise Cloud.\]](http://docs.aws.amazon.com/iot-sitewise/latest/userguide/images/gateway-open-source-nodered-publish-flow.png)


## Configure the data input node
<a name="windows-nodered-data-input-config"></a>

In this example, the data input node uses a simulated wind turbine device that generates wind speed data. This node serves as the entry point for your industrial data, whether it comes from simulated sources (as in our example) or from actual industrial equipment in production environments.

We use a custom JSON format for the data payload to provide a standardized structure that works efficiently with both local processing tools and the AWS IoT SiteWise cloud service. This format includes essential metadata like timestamps and quality indicators alongside the actual measurement values, enabling comprehensive data management and quality tracking throughout your pipeline. Import the inject node to receive simulated data in this standardized JSON format with timestamps, quality indicators, and values.

For more information on the Node-RED inject node, see the [Inject](https://nodered.org/docs/user-guide/nodes#inject) section in the *Node-RED Documentation*.

The turbine simulator generates wind speed data every second in this standardized JSON format:

**Example : Turbine data payload**  

```
{
    name: string,         // Property name/identifier
    timestamp: number,    // Epoch time in nanoseconds
    quality: "GOOD" | "UNCERTAIN" | "BAD",
    value: number | string | boolean
}
```

This format provides several benefits:
+ The `name` field identifies the specific property or measurement, allowing you to track multiple data points from the same device
+ The `timestamp` in nanoseconds ensures precise time tracking for accurate historical analysis
+ The `quality` indicator helps you filter and manage data based on its reliability
+ The flexible `value` field supports different data types to accommodate various sensor outputs

**Example : Inject node of a turbine simulator**  

```
[
    {
        "id": "string",
        "type": "inject",
        "z": "string",
        "name": "Turbine Simulator",
        "props": [
            {
                "p": "payload.timestamp",
                "v": "",
                "vt": "date"
            },
            {
                "p": "payload.quality",
                "v": "GOOD",
                "vt": "str"
            },
            {
                "p": "payload.value",
                "v": "$random()",
                "vt": "jsonata"
            },
            {
                "p": "payload.name",
                "v": "/Renton/WindFarm/Turbine/WindSpeed",
                "vt": "str"
            }
        ],
        "repeat": "1",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "x": 270,
        "y": 200,
        "wires": [
            [
                "string"
            ]
        ]
    }
]
```

## Configure a node for data translation
<a name="windows-nodered-sitewiseise-translator-config"></a>

The SiteWise Edge gateway requires data in a specific format to ensure compatibility with AWS IoT SiteWise cloud. The translator node is an important component that converts your input data to the required AWS IoT SiteWise payload format. This translation step ensures that your industrial data can be properly processed, stored, and later analyzed in the AWS IoT SiteWise cloud environment.

By standardizing the data format at this stage, you enable integration between your edge devices and the cloud service where you can use asset modeling, analytics, and visualization capabilities. Use this structure:

**Example : Payload structure for SiteWise Edge data parsing**  

```
{
  "propertyAlias": "string",  
  "propertyValues": [
    {
      "value": { 
          "booleanValue": boolean, 
          "doubleValue": number, 
          "integerValue": number,
          "stringValue": "string" 
     },
      "timestamp": {
          "timeInSeconds": number,
          "offsetInNanos": number
      },
      "quality": "GOOD" | "UNCERTAIN" | "BAD",
  }]
}
```

**Note**  
Match the `propertyAlias` to your MQTT topic hierarchy (for example, `/Renton/WindFarm/Turbine/WindSpeed`). This ensures that your data is properly associated with the correct asset property in AWS IoT SiteWise. For more information, see the "Data stream alias" concept in [AWS IoT SiteWise concepts](concept-overview.md). 

1. Import the example function node for AWS IoT SiteWise payload translation. This function handles the conversion from your standardized input format to the AWS IoT SiteWise-compatible format, ensuring proper timestamp formatting, quality indicators, and value typing.

   ```
   [
       {
           "id": "string",
           "type": "function",
           "z": "string",
           "name": "Translate to SiteWise payload",
           "func": "let input = msg.payload;\nlet output = {};\n\noutput[\"propertyAlias\"] = input.name;\n\nlet propertyVal = {}\n\nlet timeInSeconds = Math.floor(input.timestamp / 1000);\nlet offsetInNanos = (input.timestamp % 1000) * 1000000;\n\npropertyVal[\"timestamp\"] = {\n    \"timeInSeconds\": timeInSeconds,\n    \"offsetInNanos\": offsetInNanos,\n};\n\npropertyVal[\"quality\"] = input.quality\n\nlet typeNameConverter = {\n    \"number\": (x) => Number.isInteger(x) ? \"integerValue\" : \"doubleValue\",\n    \"boolean\": (x) => \"booleanValue\",\n    \"string\": (x) => \"stringValue\", \n}\nlet typeName = typeNameConverter[typeof input.value](input.value)\npropertyVal[\"value\"] = {}\npropertyVal[\"value\"][typeName] = input.value;\n\noutput[\"propertyValues\"] = [propertyVal]\n\nreturn {\n    payload: JSON.stringify(output)\n};",
           "outputs": 1,
           "timeout": "",
           "noerr": 0,
           "initialize": "",
           "finalize": "",
           "libs": [],
           "x": 530,
           "y": 200,
           "wires": [
               [
                   "string"
               ]
           ]
       }
   ]
   ```

1. Verify that the JavaScript code translates wind speed data correctly. The function performs several important tasks:
   + Extracts the property name from the input and sets it as the propertyAlias
   + Converts the timestamp from milliseconds to the required seconds and nanoseconds format
   + Preserves the quality indicator for data reliability tracking
   + Automatically detects the value type and formats it according to AWS IoT SiteWise requirements

1. Connect the node to your flow, linking it between the data input node and the MQTT publisher.

For guidance on writing a function specific to your business needs, see [Writing Functions](https://nodered.org/docs/user-guide/writing-functions) in the *Node-RED Documentation*

## Configure the MQTT publisher
<a name="windows-nodered-mqtt-publisher-config"></a>

After translation, the data is ready for publication to the SiteWise Edge MQTT broker.

Configure the MQTT publisher with these settings to send data to the SiteWise Edge MQTT broker:

**To import the MQTT out node**

1. Import an MQTT out configuration node using `"type": "mqtt out"`. MQTT out nodes let you share a broker's configuration.

1. Enter key-value pairs for information relevant to MQTT broker connection and message routing.

Import the example `mqtt out` node.

**Example**  

```
[
    {
        "id": "string",
        "type": "mqtt out",
        "z": "string",
        "name": "Publish to MQTT broker",
        "topic": "/Renton/WindFarm/Turbine/WindSpeed",
        "qos": "1",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "string",
        "x": 830,
        "y": 200,
        "wires": []
    },
    {
        "id": "string",
        "type": "mqtt-broker",
        "name": "emqx",
        "broker": "127.0.0.1",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "5",
        "keepalive": 15,
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]
```

The example MQTT out node creates the MQTT connection with the following information:
+ Server: `127.0.0.1`
+ Port: `1883`
+ Protocol: `MQTT V5`

Then, the MQTT out node configures message routing with the following information:
+ Topic: `/Renton/WindFarm/Turbine/WindSpeed`
+ QoS: `1`

## Deploy and verify the nodes
<a name="windows-verify-deployment"></a>

After configuring the three data publish flow nodes, follow these steps to deploy the flow and verify that data is being transmitted correctly to AWS IoT SiteWise

**To deploy and verify connections**

1. Connect the three nodes as shown in the data publish flow.  
![\[Data publish flow diagram showing input from turbine simulator to AWS IoT SiteWise to MQTT broker.\]](http://docs.aws.amazon.com/iot-sitewise/latest/userguide/images/gateway-open-source-nodered-publish-flow.png)

1. Choose **Deploy** to apply all node connection changes.

1. Navigate to the [AWS IoT SiteWise console](https://console.aws.amazon.com/iotsitewise/) and choose **Data streams**.

1. Ensure **Alias prefix** is selected in the dropdown menu. Then, search for the `/Renton/WindFarm/Turbine/WindSpeed` alias.

If you see the correct alias in your search, you have deployed the flow and verified data transmission.

# Configure the data retention flow
<a name="windows-nodered-data-retention-flow"></a>

The data retention flow is can be used to maintain operational visibility at the edge. This is useful during network disruptions or when you need immediate access to your data. This flow subscribes to the MQTT broker to receive device data, converts it to InfluxDB® format, and stores it locally. By implementing this flow, you create a resilient local data store that operators can access without cloud dependencies, enabling real-time monitoring and decision-making at the edge.

The flow consists of three key components working together to ensure your data is properly captured and stored:
+ **MQTT subscription client** - Receives data from the broker, ensuring you capture all relevant industrial data
+ **InfluxDB translator** - Converts AWS IoT SiteWise payload to InfluxDB format, preparing the data for efficient time-series storage
+ **InfluxDB writer** - Handles local storage, ensuring data persistence and availability for local applications

![\[Node-RED data retention flow\]](http://docs.aws.amazon.com/iot-sitewise/latest/userguide/images/gateway-open-source-nodered-data-retention.png)


## Set up the MQTT subscription client
<a name="windows-nodered-mqtt-subscriber"></a>
+ Configure the MQTT subscription client in Node-RED to receive data from the MQTT EMQX broker in AWS IoT SiteWise by importing the example below.  
**Example : MQTT in node**  

  ```
  [
      {
          "id": "string",
          "type": "mqtt in",
          "z": "string",
          "name": "Subscribe to MQTT broker",
          "topic": "/Renton/WindFarm/Turbine/WindSpeed",
          "qos": "1",
          "datatype": "auto-detect",
          "broker": "string",
          "nl": false,
          "rap": true,
          "rh": 0,
          "inputs": 0,
          "x": 290,
          "y": 340,
          "wires": [
              [
                  "string"
              ]
          ]
      },
      {
          "id": "string",
          "type": "mqtt-broker",
          "name": "emqx",
          "broker": "127.0.0.1",
          "port": "1883",
          "clientid": "",
          "autoConnect": true,
          "usetls": false,
          "protocolVersion": "5",
          "keepalive": 15,
          "cleansession": true,
          "autoUnsubscribe": true,
          "birthTopic": "",
          "birthQos": "0",
          "birthPayload": "",
          "birthMsg": {},
          "closeTopic": "",
          "closePayload": "",
          "closeMsg": {},
          "willTopic": "",
          "willQos": "0",
          "willPayload": "",
          "willMsg": {},
          "userProps": "",
          "sessionExpiry": ""
      }
  ]
  ```

This subscription ensures that all relevant data published to the broker is captured for local storage, providing a complete record of your industrial operations. The node uses the same MQTT connection parameters as the [Configure the MQTT publisher](windows-nodered-data-publish-flow.md#windows-nodered-mqtt-publisher-config) section, with the following subscription settings:
+ Topic – `/Renton/WindFarm/Turbine/WindSpeed`
+ QoS – `1`

For more information, see [Connect to an MQTT Broker](https://cookbook.nodered.org/mqtt/connect-to-broker) in the *Node-RED Documentation*.

## Configure the InfluxDB translator
<a name="windows-nodered-influxdb-translator"></a>

InfluxDB organizes data using [tags](https://docs.influxdata.com/influxdb/v1/concepts/glossary/#tag) for indexing and [fields](https://docs.influxdata.com/influxdb/v1/concepts/glossary/#field) for values. This organization optimizes query performance and storage efficiency for time-series data. Import the example function node that contains JavaScript code to convert AWS IoT SiteWise payload to InfluxDB format. The translator splits the properties into two groups:
+ Tags – Quality and name properties for efficient indexing
+ Fields – Timestamp (in milliseconds since epoch) and value

**Example : Function node of translating to an InfluxDB payload**  

```
[
    {
        "id": "string",
        "type": "function",
        "z": "string",
        "name": "Translate to InfluxDB payload",
        "func": "let data = msg.payload;\n\nlet timeInSeconds = data.propertyValues[0].timestamp.timeInSeconds;\nlet offsetInNanos = data.propertyValues[0].timestamp.offsetInNanos;\nlet timestampInMilliseconds = (timeInSeconds * 1000) + (offsetInNanos / 1000000);\n\nmsg.payload = [\n    {\n        \"timestamp(milliseconds_since_epoch)\": timestampInMilliseconds,\n        \"value\": data.propertyValues[0].value.doubleValue\n    },\n    {\n        \"name\": data.propertyAlias,\n        \"quality\": data.propertyValues[0].quality\n    }\n]\n\nreturn msg",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 560,
        "y": 340,
        "wires": [
            [
                "string"
            ]
        ]
    }
]
```

For additional configuration options, see the [node-red-contrib-influxdb](https://github.com/mblackstock/node-red-contrib-influxdb) in the Node-RED GitHub repository.

## Set up the InfluxDB writer
<a name="windows-nodered-influxdb-writer"></a>

The InfluxDB writer node is the final component in your data retention flow, responsible for storing your industrial data in the local InfluxDB database. This local storage is important for maintaining operational visibility during network disruptions and providing immediate access to data for time-critical applications.

1. Install the node-red-contrib-influxdb package through the Manage palette option. This package provides the necessary nodes for connecting Node-RED with InfluxDB.

1. Add an InfluxDB out node to your flow. This node will handle the actual writing of data to your InfluxDB database.

1. Configure the server properties to establish a secure connection to your InfluxDB instance:

   1. Set Version to 2.0 - This specifies that you're connecting to InfluxDB v2.x, which uses a different API than earlier versions

   1. Set URL to `http://127.0.0.1:8086` - This points to your local InfluxDB instance

   1. Enter your InfluxDB authentication token. This secure token authorizes the connection to your database. You generated the token during the [Set up local storage with InfluxDB](windows-influxdb-setup.md) procedure.

1. Specify the storage location parameters to define where and how your data will be stored:

   1. Enter your InfluxDB Organization name – The organization is a workspace for a group of users, where your buckets and dashboards belong. For more information, see [Manage organizations](https://docs.influxdata.com/influxdb/v2/admin/organizations/) in the *InfluxData Documentation*.

   1. Specify the InfluxDB Bucket (for example, `WindFarmData`) – The bucket is equivalent to a database in traditional systems, serving as a container for your time series data

   1. Set the InfluxDB Measurement (for example, `TurbineData`) – The measurement is similar to a table in relational databases, organizing related data points

**Note**  
Find your organization name in the InfluxDB instance's left sidebar. The organization, bucket, and measurement concepts are fundamental to InfluxDB's data organization model. For more information, see the [InfluxDB documentation](https://docs.influxdata.com/influxdb/v2/admin/organizations/).

## Deploy and verify the retention flow
<a name="windows-nodered-retention-deploy"></a>

After configuring all components of the data retention flow, you need to deploy and verify that the system is working correctly. This verification ensures that your industrial data is being properly stored locally for immediate access and analysis.

1. Connect the three nodes as shown in the data retention flow diagram. This creates a complete pipeline from data subscription to local storage.  
![\[Node-RED data retention flow\]](http://docs.aws.amazon.com/iot-sitewise/latest/userguide/images/gateway-open-source-nodered-data-retention.png)

1. Choose **Deploy** to apply your changes and activate the flow. This starts the data collection and storage process.

1. Use the InfluxDB Data Explorer to query and visualize your data. This tool allows you to verify that data is being properly stored and to create initial visualizations of your time series data.

   In the Data Explorer, you should be able to see your wind speed measurements being recorded over time, confirming that the entire pipeline from data generation to local storage is functioning correctly. 

   For more information, see [Query in Data Explorer](https://docs.influxdata.com/influxdb/v2/query-data/execute-queries/data-explorer/) in the *InfluxData Documentation*.

With both the data publish flow and data retention flow deployed, you now have a complete system that sends data to the AWS IoT SiteWise cloud while maintaining a local copy for immediate access and resilience. This dual-path approach ensures that you get the benefits of cloud-based analytics and storage while maintaining operational visibility at the edge.

# Set up Grafana for SiteWise Edge
<a name="windows-grafana"></a>

 Grafana® lets you create local real-time monitoring dashboards for your industrial data. By visualizing the data stored in InfluxDB®, you can provide operators with immediate insights into equipment performance, process efficiency, and potential issues. This visibility at the edge is important for time-sensitive operations and maintaining continuity during network disruptions.

## Configure the data source
<a name="windows-grafana-data-source-config"></a>

Connecting Grafana to your InfluxDB database creates a powerful visualization layer for your industrial data. This connection enables real-time monitoring dashboards that operators can use to make informed decisions without cloud dependencies.

1. Access your Grafana instance locally by navigating to [http://127.0.0.1:3000](http://127.0.0.1:3000) in your browser. If enabling TLS is required, you can refer to [Set up Grafana HTTPS for secure web traffic](https://grafana.com/docs/grafana/latest/setup-grafana/set-up-https/) in the *Grafana Labs Documentation*.

1. Add an InfluxDB data source pointing to the InfluxDB time series bucket where Node-RED writes data. For example, `WindFarmData`. This connection establishes the link between your stored data and the visualization platform.

1. For detailed instructions, see [Configure the InfluxDB data source](https://grafana.com/docs/grafana/latest/datasources/influxdb/configure-influxdb-data-source/) in the *Grafana Labs Documentation*.

### Create a Grafana dashboard for SiteWise Edge data
<a name="windows-grafana-create-dashboard"></a>

Creating a dashboard is the final step in building your local monitoring solution. Dashboards provide visual representations of your industrial data, making it easier to identify trends, anomalies, and potential issues at a glance.
+ Follow the guide to create a dashboard. For more information, see [Build your first dashboard](https://grafana.com/docs/grafana/latest/getting-started/build-first-dashboard/) in the *Grafana Labs Documentation*. This template assumes your bucket is named `WindFarmData` and measurement is `TurbineData`.

  You can also use the quick start guide by importing the provided example dashboard template to quickly create a dashboard with a time series plot for the data that Node-RED generates in previous section. This template provides a starting point that you can customize to meet your specific monitoring needs.

  ```
  {
    "__inputs": [
      {
        "name": "DS_WINDFARM-DEMO",
        "label": "windfarm-demo",
        "description": "",
        "type": "datasource",
        "pluginId": "influxdb",
        "pluginName": "InfluxDB"
      }
    ],
    "__elements": {},
    "__requires": [
      {
        "type": "grafana",
        "id": "grafana",
        "name": "Grafana",
        "version": "11.6.0-pre"
      },
      {
        "type": "datasource",
        "id": "influxdb",
        "name": "InfluxDB",
        "version": "1.0.0"
      },
      {
        "type": "panel",
        "id": "timeseries",
        "name": "Time series",
        "version": ""
      }
    ],
    "annotations": {
      "list": [
        {
          "builtIn": 1,
          "datasource": {
            "type": "grafana",
            "uid": "-- Grafana --"
          },
          "enable": true,
          "hide": true,
          "iconColor": "rgba(0, 211, 255, 1)",
          "name": "Annotations & Alerts",
          "type": "dashboard"
        }
      ]
    },
    "editable": true,
    "fiscalYearStartMonth": 0,
    "graphTooltip": 0,
    "id": null,
    "links": [],
    "panels": [
      {
        "datasource": {
          "type": "influxdb",
          "uid": "${DS_WINDFARM-DEMO}"
        },
        "fieldConfig": {
          "defaults": {
            "color": {
              "mode": "palette-classic"
            },
            "custom": {
              "axisBorderShow": false,
              "axisCenteredZero": false,
              "axisColorMode": "text",
              "axisLabel": "",
              "axisPlacement": "auto",
              "barAlignment": 0,
              "barWidthFactor": 0.6,
              "drawStyle": "line",
              "fillOpacity": 0,
              "gradientMode": "none",
              "hideFrom": {
                "legend": false,
                "tooltip": false,
                "viz": false
              },
              "insertNulls": false,
              "lineInterpolation": "linear",
              "lineWidth": 1,
              "pointSize": 5,
              "scaleDistribution": {
                "type": "linear"
              },
              "showPoints": "auto",
              "spanNulls": false,
              "stacking": {
                "group": "A",
                "mode": "none"
              },
              "thresholdsStyle": {
                "mode": "off"
              }
            },
            "mappings": [],
            "thresholds": {
              "mode": "absolute",
              "steps": [
                {
                  "color": "green"
                },
                {
                  "color": "red",
                  "value": 80
                }
              ]
            }
          },
          "overrides": []
        },
        "gridPos": {
          "h": 8,
          "w": 12,
          "x": 0,
          "y": 0
        },
        "id": 1,
        "options": {
          "legend": {
            "calcs": [],
            "displayMode": "list",
            "placement": "bottom",
            "showLegend": true
          },
          "tooltip": {
            "hideZeros": false,
            "mode": "single",
            "sort": "none"
          }
        },
        "pluginVersion": "11.6.0-pre",
        "targets": [
          {
            "datasource": {
              "type": "influxdb",
              "uid": "${DS_WINDFARM-DEMO}"
            },
            "query": "from(bucket: \"WindFarmData\")\n  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n  |> filter(fn: (r) => r[\"_measurement\"] == \"TurbineData\")\n  |> filter(fn: (r) => r[\"_field\"] == \"value\")\n  |> filter(fn: (r) => r[\"name\"] == \"/Renton/WindFarm/Turbine/WindSpeed\")\n  |> filter(fn: (r) => r[\"quality\"] == \"GOOD\")\n  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n  |> yield(name: \"mean\")",
            "refId": "A"
          }
        ],
        "title": "Panel Title",
        "type": "timeseries"
      }
    ],
    "schemaVersion": 41,
    "tags": [],
    "templating": {
      "list": []
    },
    "time": {
      "from": "now-6h",
      "to": "now"
    },
    "timepicker": {},
    "timezone": "browser",
    "title": "demo dashboard",
    "uid": "fejc0t08o6d4wb",
    "version": 1,
    "weekStart": ""
  }
  ```

# Set up open-source integrations with Docker (Linux)
<a name="linux-docker-setup"></a>

For a streamlined deployment process, you can use Docker to set up Node-RED®, InfluxDB®, and Grafana® on a Linux environment. This method uses pre-configured containers, allowing for rapid deployment and easier management of the components.

## Docker setup prerequisites
<a name="linux-docker-prerequisites"></a>

Before you begin, verify that have the following:
+ An MQTT-enabled, V3 gateway. For more information, see [MQTT-enabled, V3 gateways for AWS IoT SiteWise Edge](mqtt-enabled-v3-gateway.md).
+ The Docker Compose plugin. For installation steps, see [Install the Docker Compose plugin](https://docs.docker.com/compose/install/linux/) in the *Docker* Manuals documentation.

## Deploy the services
<a name="linux-docker-deployment"></a>

This deployment runs SiteWise Edge, InfluxDB, Node-RED, and Grafana on the same host.

### Set up the environment
<a name="linux-docker-env-setup"></a>

1. Gain root access:

   ```
   sudo -i
   ```

1. Create a .env file or export these environment variables:

   ```
   export INFLUXDB_PASSWORD=your-secure-influxdb-password
   export INFLUXDB_TOKEN=your-secure-influxdb-token
   export GRAFANA_PASSWORD=your-secure-grafana-password
   ```

### Configure the Docker network
<a name="linux-docker-network-config"></a>
+ Create a bridge network using the name `SiteWiseEdgeNodeRedDemoNetwork`.

  ```
  docker network create --driver=bridge SiteWiseEdgeNodeRedDemoNetwork
  ```

### Prepare the Docker Compose file
<a name="linux-docker-compose-file"></a>

Copy the contents of the following YAML file to your SiteWise Edge gateway device.

#### Expand to view the Docker Compose YAML file example
<a name="collapsible-section-docker-compose-file"></a>

```
services:
  influxdb:
    image: influxdb:latest
    container_name: influxdb
    ports:
      - "127.0.0.1:8086:8086"
    volumes:
      - influxdb-storage:/.influxdbv2
    environment:
      - DOCKER_INFLUXDB_INIT_MODE=setup
      - DOCKER_INFLUXDB_INIT_USERNAME=admin
      - DOCKER_INFLUXDB_INIT_PASSWORD=${INFLUXDB_PASSWORD}
      - DOCKER_INFLUXDB_INIT_ORG=iot-sitewise-edge
      - DOCKER_INFLUXDB_INIT_BUCKET=WindFarmData
      - DOCKER_INFLUXDB_INIT_RETENTION=0
      - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=${INFLUXDB_TOKEN}
    networks:
      - SiteWiseEdgeNodeRedDemoNetwork
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - grafana-storage:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
      - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
      - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
      - GF_PATHS_CONFIG=/etc/grafana/grafana.ini
      - GF_LOG_LEVEL=info
    configs:
      - source: grafana_datasource
        target: /etc/grafana/provisioning/datasources/influxdb.yaml
      - source: grafana_preload_dashboard_config
        target: /etc/grafana/provisioning/dashboards/dashboard.yml
      - source: grafana_preload_dashboard
        target: /etc/grafana/provisioning/dashboards/demo_dashboard.json
    depends_on:
      - influxdb
    networks:
      - SiteWiseEdgeNodeRedDemoNetwork
    restart: unless-stopped

  nodered:
    build:
      context: .
      dockerfile_inline: |
        FROM nodered/node-red:latest
        RUN npm install node-red-contrib-influxdb
    container_name: nodered
    ports:
      - "127.0.0.1:1880:1880"
    volumes:
      - node_red_data:/data
    environment:
      - NODE_RED_ENABLE_SAFE_MODE=false
      - NODE_RED_ENABLE_PALETTE_EDIT=true
      - NODE_RED_AUTO_INSTALL_MODULES=true
    configs:
      - source: nodered_flows
        target: /data/flows.json
      - source: nodered_settings
        target: /data/settings.js
      - source: nodered_flows_cred
        target: /data/flows_cred.json
    depends_on:
      - influxdb
    networks:
      - SiteWiseEdgeNodeRedDemoNetwork
    restart: unless-stopped

volumes:
  influxdb-storage:
  grafana-storage:
  node_red_data:

networks:
  SiteWiseEdgeNodeRedDemoNetwork:
    external: true

configs:
  grafana_datasource:
    content: |
      apiVersion: 1
      datasources:
        - name: windfarm-demo
          type: influxdb
          access: proxy
          url: http://influxdb:8086
          jsonData:
            version: Flux
            organization: iot-sitewise-edge
            defaultBucket: WindFarmData
            tlsSkipVerify: true
          secureJsonData:
            token: ${INFLUXDB_TOKEN}
          editable: false

  grafana_preload_dashboard_config:
    content: |
      apiVersion: 1
      providers:
        - name: "Dashboard provider"
          orgId: 1
          type: file
          options: 
            path: /etc/grafana/provisioning/dashboards

  grafana_preload_dashboard:
    content: |
      {
        "annotations": {
          "list": [
            {
              "builtIn": 1,
              "datasource": {
                "type": "grafana",
                "uid": "-- Grafana --"
              },
              "enable": true,
              "hide": true,
              "iconColor": "rgba(0, 211, 255, 1)",
              "name": "Annotations & Alerts",
              "type": "dashboard"
            }
          ]
        },
        "editable": true,
        "fiscalYearStartMonth": 0,
        "graphTooltip": 0,
        "id": 1,
        "links": [],
        "panels": [
          {
            "datasource": {
              "type": "influxdb",
              "uid": "PEB0DCBF338B3CEB2"
            },
            "fieldConfig": {
              "defaults": {
                "color": {
                  "mode": "palette-classic"
                },
                "custom": {
                  "axisBorderShow": false,
                  "axisCenteredZero": false,
                  "axisColorMode": "text",
                  "axisLabel": "",
                  "axisPlacement": "auto",
                  "barAlignment": 0,
                  "barWidthFactor": 0.6,
                  "drawStyle": "line",
                  "fillOpacity": 0,
                  "gradientMode": "none",
                  "hideFrom": {
                    "legend": false,
                    "tooltip": false,
                    "viz": false
                  },
                  "insertNulls": false,
                  "lineInterpolation": "linear",
                  "lineWidth": 1,
                  "pointSize": 5,
                  "scaleDistribution": {
                    "type": "linear"
                  },
                  "showPoints": "auto",
                  "spanNulls": false,
                  "stacking": {
                    "group": "A",
                    "mode": "none"
                  },
                  "thresholdsStyle": {
                    "mode": "off"
                  }
                },
                "mappings": [],
                "thresholds": {
                  "mode": "absolute",
                  "steps": [
                    {
                      "color": "green"
                    },
                    {
                      "color": "red",
                      "value": 80
                    }
                  ]
                }
              },
              "overrides": []
            },
            "gridPos": {
              "h": 8,
              "w": 12,
              "x": 0,
              "y": 0
            },
            "id": 1,
            "options": {
              "legend": {
                "calcs": [],
                "displayMode": "list",
                "placement": "bottom",
                "showLegend": true
              },
              "tooltip": {
                "hideZeros": false,
                "mode": "single",
                "sort": "none"
              }
            },
            "pluginVersion": "11.6.0",
            "targets": [
              {
                "datasource": {
                  "type": "influxdb",
                  "uid": "PEB0DCBF338B3CEB2"
                },
                "query": "from(bucket: \"WindFarmData\")\n  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n  |> filter(fn: (r) => r[\"_measurement\"] == \"TurbineData\")\n  |> filter(fn: (r) => r[\"_field\"] == \"value\")\n  |> filter(fn: (r) => r[\"name\"] == \"/Renton/WindFarm/Turbine/WindSpeed\")\n  |> filter(fn: (r) => r[\"quality\"] == \"GOOD\")\n  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n  |> yield(name: \"mean\")",
                "refId": "A"
              }
            ],
            "title": "Wind Speed",
            "type": "timeseries"
          }
        ],
        "preload": false,
        "schemaVersion": 41,
        "tags": [],
        "templating": {
          "list": []
        },
        "time": {
          "from": "now-6h",
          "to": "now"
        },
        "timepicker": {},
        "timezone": "browser",
        "title": "Demo Dashboard",
        "uid": "eejtureqjo9a8c",
        "version": 2
      }

  nodered_flows:
    content: |
      [
        {
          "id": "95fce448fdd43b47",
          "type": "tab",
          "label": "Demo Flow",
          "disabled": false,
          "info": ""
        },
        {
          "id": "5f63740b66af3386",
          "type": "mqtt out",
          "z": "95fce448fdd43b47",
          "name": "Publish to MQTT broker",
          "topic": "/Renton/WindFarm/Turbine/WindSpeed",
          "qos": "1",
          "retain": "",
          "respTopic": "",
          "contentType": "",
          "userProps": "",
          "correl": "",
          "expiry": "",
          "broker": "5744207557fa19be",
          "x": 830,
          "y": 200,
          "wires": []
        },
        {
          "id": "8f2eb590d596679b",
          "type": "function",
          "z": "95fce448fdd43b47",
          "name": "Translate to SiteWise payload",
          "func": "let input = msg.payload;\nlet output = {};\n\noutput[\"propertyAlias\"] = input.name;\n\nlet propertyVal = {}\n\nlet timeInSeconds = Math.floor(input.timestamp / 1000);\nlet offsetInNanos = (input.timestamp % 1000) * 1000000;\n\npropertyVal[\"timestamp\"] = {\n    \"timeInSeconds\": timeInSeconds,\n    \"offsetInNanos\": offsetInNanos,\n};\n\npropertyVal[\"quality\"] = input.quality\n\nlet typeNameConverter = {\n    \"number\": (x) => Number.isInteger(x) ? \"integerValue\" : \"doubleValue\",\n    \"boolean\": (x) => \"booleanValue\",\n    \"string\": (x) => \"stringValue\", \n}\nlet typeName = typeNameConverter[typeof input.value](input.value)\npropertyVal[\"value\"] = {}\npropertyVal[\"value\"][typeName] = input.value;\n\noutput[\"propertyValues\"] = [propertyVal]\n\nreturn {\n    payload: JSON.stringify(output)\n};",
          "outputs": 1,
          "timeout": "",
          "noerr": 0,
          "initialize": "",
          "finalize": "",
          "libs": [],
          "x": 530,
          "y": 200,
          "wires": [
            [
              "5f63740b66af3386"
            ]
          ]
        },
        {
          "id": "4b78cbdea5e3258c",
          "type": "inject",
          "z": "95fce448fdd43b47",
          "name": "Turbine Simulator",
          "props": [
            {
              "p": "payload.timestamp",
              "v": "",
              "vt": "date"
            },
            {
              "p": "payload.quality",
              "v": "GOOD",
              "vt": "str"
            },
            {
              "p": "payload.value",
              "v": "$$random()",
              "vt": "jsonata"
            },
            {
              "p": "payload.name",
              "v": "/Renton/WindFarm/Turbine/WindSpeed",
              "vt": "str"
            }
          ],
          "repeat": "1",
          "crontab": "",
          "once": false,
          "onceDelay": "",
          "topic": "",
          "x": 270,
          "y": 200,
          "wires": [
            [
              "8f2eb590d596679b"
            ]
          ]
        },
        {
          "id": "b658bf337ea2e316",
          "type": "influxdb out",
          "z": "95fce448fdd43b47",
          "influxdb": "2f1c38495035d2e4",
          "name": "Store data in InfluxDB",
          "measurement": "TurbineData",
          "precision": "",
          "retentionPolicy": "",
          "database": "",
          "retentionPolicyV18Flux": "",
          "org": "iot-sitewise-edge",
          "bucket": "WindFarmData",
          "x": 840,
          "y": 340,
          "wires": []
        },
        {
          "id": "9432d39af35b202f",
          "type": "function",
          "z": "95fce448fdd43b47",
          "name": "Translate to InfluxDB payload",
          "func": "let data = msg.payload;\n\nlet timeInSeconds = data.propertyValues[0].timestamp.timeInSeconds;\nlet offsetInNanos = data.propertyValues[0].timestamp.offsetInNanos;\nlet timestampInMilliseconds = (timeInSeconds * 1000) + (offsetInNanos / 1000000);\n\nmsg.payload = [\n    {\n        \"timestamp(milliseconds_since_epoch)\": timestampInMilliseconds,\n        \"value\": data.propertyValues[0].value.doubleValue\n    },\n    {\n        \"name\": data.propertyAlias,\n        \"quality\": data.propertyValues[0].quality\n    }\n]\n\nreturn msg",
          "outputs": 1,
          "timeout": "",
          "noerr": 0,
          "initialize": "",
          "finalize": "",
          "libs": [],
          "x": 560,
          "y": 340,
          "wires": [
            [
              "b658bf337ea2e316"
            ]
          ]
        },
        {
          "id": "b689403d2c80816b",
          "type": "mqtt in",
          "z": "95fce448fdd43b47",
          "name": "Subscribe to MQTT broker",
          "topic": "/Renton/WindFarm/Turbine/WindSpeed",
          "qos": "1",
          "datatype": "auto-detect",
          "broker": "5744207557fa19be",
          "nl": false,
          "rap": true,
          "rh": 0,
          "inputs": 0,
          "x": 290,
          "y": 340,
          "wires": [
            [
              "9432d39af35b202f"
            ]
          ]
        },
        {
          "id": "4f59bed8e829fc35",
          "type": "comment",
          "z": "95fce448fdd43b47",
          "name": "Data Publish Flow",
          "info": "dfgh",
          "x": 270,
          "y": 160,
          "wires": []
        },
        {
          "id": "b218c7fc58c8b6e7",
          "type": "comment",
          "z": "95fce448fdd43b47",
          "name": "Data Retention flow",
          "info": "",
          "x": 270,
          "y": 300,
          "wires": []
        },
        {
          "id": "5744207557fa19be",
          "type": "mqtt-broker",
          "name": "emqx",
          "broker": "emqx",
          "port": "1883",
          "clientid": "",
          "autoConnect": true,
          "usetls": false,
          "protocolVersion": "5",
          "keepalive": 15,
          "cleansession": true,
          "autoUnsubscribe": true,
          "birthTopic": "",
          "birthQos": "0",
          "birthPayload": "",
          "birthMsg": {},
          "closeTopic": "",
          "closePayload": "",
          "closeMsg": {},
          "willTopic": "",
          "willQos": "0",
          "willPayload": "",
          "willMsg": {},
          "userProps": "",
          "sessionExpiry": ""
        },
        {
          "id": "2f1c38495035d2e4",
          "type": "influxdb",
          "hostname": "influxdb",
          "port": 8086,
          "protocol": "http",
          "database": "",
          "name": "InfluxDB",
          "usetls": false,
          "tls": "",
          "influxdbVersion": "2.0",
          "url": "http://influxdb:8086",
          "timeout": "",
          "rejectUnauthorized": false
        }
      ]

  nodered_flows_cred:
    content: |
      {
        "2f1c38495035d2e4": {
          "token": "${INFLUXDB_TOKEN}"
        }
      }

  nodered_settings:
    content: |
      module.exports = {
        flowFile: 'flows.json',
        credentialSecret: false,
        adminAuth: null,
        editorTheme: {
          projects: {
            enabled: false
          }
        }
      }
```

### Update the SiteWise Edge deployment
<a name="w2aac17c19c19c26c27b7c11"></a>

1. Navigate to the [AWS IoT console](https://console.aws.amazon.com/iot/)

1. Choose **Greengrass devices** in the left navigation menu under the **Manage** section, then **Core devices**.

1. Select the core device connected to your SiteWise Edge Gateway.

1. Choose the **Deployments** tab, then select the **Deployment ID** value.

1. Choose **Actions**, then select **Revise**. 

1. Read the pop up message and then choose **Revise Deployment**.

1. In **Step 2 - Select components**, select the following components and then choose **Next**.
   + `aws.greengrass.clientdevices.mqtt.EMQX`
   + `aws.iot.SiteWiseEdgePublisher`

1. In **Step 3 - Configure components**, select the `aws.greengrass.clientdevices.mqtt.EMQX` component value and add the following network configuration:

   ```
   {
       "emqxConfig": {
           "authorization": {
               "no_match": "allow"
           },
           "listeners": {
               "tcp": {
                   "default": {
                       "enabled": true,
                       "enable_authn": false
                   }
               }
           }
       },
       "authMode": "bypass",
       "dockerOptions": "-p 127.0.0.1:1883:1883 --network=SiteWiseEdgeNodeRedDemoNetwork",
       "requiresPrivilege": "true"
   }
   ```

1. Choose **Next**.

1. In **Step 4 - Configure advanced settings**, choose **Next**.

1. Choose **Deploy**

### Launch the services
<a name="linux-docker-launch"></a>

1. Start the services using the Docker Compose file. Run the following command under the directory containing the `compose.yaml` file.

   ```
   docker compose up -d
   ```

1. Create an SSH tunnel to access the services:

   ```
   ssh -i path_to_your_ssh_key -L 1880:127.0.0.1:1880 -L 3000:127.0.0.1:3000 -L 8086:127.0.0.1:8086 username@gateway_ip_address
   ```

This deployment creates the following services in the `SiteWiseEdgeNodeRedDemoNetwork network`:

**InfluxDB v2 (port 8086)**  
Includes pre-configured organization (iot-sitewise-edge), WindFarmData InfluxDB bucket, and admin credentials

**Node-RED (port 1880)**  
Includes InfluxDB nodes and pre-configured flows for AWS IoT SiteWise integration

**Grafana (port 3000)**  
Includes admin user, InfluxDB datasource, and monitoring dashboard

### Access the services
<a name="linux-docker-access-services"></a>

After deployment, access the services using the following URLs and credentials:

**Note**  
You can access each service from your host or the gateway machine.


**Service access details**  

| Service | URL | Credentials | 
| --- | --- | --- | 
| Node-RED | [http://127.0.0.1:1880](http://127.0.0.1:1880) | No credentials required | 
| InfluxDB | [http://127.0.0.1:8086](http://127.0.0.1:8086) |  Username: admin Password: \$1INFLUXDB\$1PASSWORD  | 
| Grafana | [http://127.0.0.1:3000](http://127.0.0.1:3000) |  Username: admin Password: \$1GRAFANA\$1PASSWORD  | 

## Verify the deployment
<a name="linux-docker-verify-deployment"></a>

To ensure your deployment is successful, perform the following checks:

1. For Node-RED, verify the presence of two preloaded flows:
   + Data publish flow
   + Data retention flow

1. For AWS IoT SiteWise, in the AWS IoT SiteWise console, confirm the presence of a data stream with the alias `/Renton/WindFarm/Turbine/WindSpeed`.

1. For InfluxDB, use the Data Explorer to verify data storage in the `TurbineData` measurement within the `WindFarmData` bucket.

1. For Grafana, view the dashboard to confirm the display of time series data generated from Node-RED.

# Process data for open source integrations
<a name="open-source-data-processing-open-source"></a>

The data can be processed (such as transformation or aggregation), at different stages using various tools, each serving different monitoring requirements.

## Process data with Node-RED nodes
<a name="open-source-nodered-nodes"></a>

Transform your data in real time using Node-RED® built-in processing nodes. Configure these nodes through the Node-RED console to create your data pipeline.

### Data transformation nodes
<a name="open-source-data-transformation-nodes"></a>

Transform individual data points, similar to Transforms in AWS IoT SiteWise, using these nodes:
+ **change node** - Performs simple value modifications on your data.
+ **function node** - Enables custom JavaScript transformations for complex data processing.

### Metrics calculation nodes
<a name="open-source-metrics-calculation-nodes"></a>

Combine multiple data points into a single output, similar to Metrics in AWS IoT SiteWise, using these nodes:
+ **batch node** - Groups multiple messages for batch processing.
+ **join node** - Combines multiple data streams into a single output.
+ **aggregator node** - Calculates aggregate metrics from multiple data points.

For additional node options, see the [Node-RED Library](https://flows.nodered.org/).

## Create InfluxDB tasks
<a name="open-source-influxdb-tasks"></a>

While Node-RED excels at basic data processing with quick setup, complex metric calculations may become challenging in flow-based programming. InfluxDB® Tasks provide an alternative through scheduled Flux scripts for advanced processing needs.

Use InfluxDB Tasks for:
+ Statistical aggregations across large datasets
+ Mathematical operations on multiple properties
+ Derived measurements from multiple sources

### Task features
<a name="open-source-task-features"></a>
+ **Scheduled Execution** - Run tasks based on cron expressions
+ **Batch Processing** - Optimize operations for time-series data
+ **Error Recovery** - Automatically retry failed operations
+ **Monitoring** - Track execution through detailed logs

Manage tasks through the InfluxDB UI, API, or CLI. For more information, see [Process data with InfluxDB tasks](https://docs.influxdata.com/influxdb/cloud/process-data/).

## Use Grafana transformations
<a name="open-source-grafana-transformations"></a>

Transform data visualization in Grafana® without modifying the source data in InfluxDB. Grafana transformations apply only to the visualization layer.
+ **Visual Builder** - Create transformations without writing code
+ **Live Preview** - View transformation results in real time
+ **Multi-Source** - Process data from multiple database sources
+ **Storage Efficient** - Transform data at visualization time without storing intermediary results

For more information, see [Transform data](https://grafana.com/docs/grafana/latest/panels/transform-data/).

## Troubleshooting open-source integrations
<a name="open-source-troubleshoot"></a>

For more information on troubleshooting topics related to open source integrations for SiteWise Edge gateways, see [Troubleshooting open-source integrations at the Edge](troubleshooting-gateway.md#open-source-troubleshooting).