Skip to content

how to build an iot dashboard using aws iot twinmaker and iot application kit

liyuanqian edited this page Jul 14, 2023 · 3 revisions

This tutorial explains how to build an IoT dashboard application in React using AWS IoT TwinMaker (TwinMaker) and IoT Application Kit (IoT AppKit).

TwinMaker is an AWS IoT service that you can use to build operational digital twins of physical and digital systems.

IoT AppKit is an open-source library that offers a variety of React components and a TwinMaker data source specifically developed to enable your IoT and digital twin applications.

Prerequisites

To work with TwinMaker in this tutorial, you will need:

  1. An AWS Account and the necessary permissions to use AWS IoT TwinMaker. If you already have AWS IoT TwinMaker set up, you can proceed to the next section. Otherwise, follow the instructions to set up an account and configure authentication.

  2. You have created an AWS IoT TwinMaker workspace. For more information on workspace creation, read the workspace creation topic.

  3. The Cookie Factory v2 demo deployed to your AWS account. Resources created for the demo will be used in this tutorial.

  4. Minimum versions of Node.js, npm, and an IDE or simple code editor installed.

    • Node.js 16+. npm recommends using a Node version manager, e.g. nvm to install Node.js and npm.

    • npm 8+. npm is automatically installed when you install Node.js or a Node.js version manager.

    • An IDE or code editor of your choice, e.g. AWS Cloud9 or Visual Studio Code.

  5. A React starter project. To ensure your project is properly configured for this tutorial, complete the Create a basic web application with React, Typescript, and webpack tutorial to create a basic React project with the required dependencies and configuration.

  6. Experience building a React application with IoT AppKit. If you would like learn how to build applications with React and IoT AppKit, complete the How to use IoT Application Kit in a React web application tutorial.

Goal

Create an IoT dashboard to monitor the Cookie Factory Freezer Tunnel.

Build an IoT dashboard using IoT AppKit

Installing IoT AppKit packages

IoT AppKit is a collection of npm packages you install individually as needed based on your application requirements. For the dashboard application, the following packages are required.

npm install -S @iot-app-kit/react-components @iot-app-kit/source-iottwinmaker

Importing IoT AppKit modules

import type { DurationViewport, StyleSettingsMap, Threshold } from '@iot-app-kit/core';
import { LineChart, StatusTimeline, TimeSync, WebglContext } from '@iot-app-kit/react-components';
import { initialize, type TwinMakerEntityHistoryQuery } from '@iot-app-kit/source-iottwinmaker';

Importing IoT AppKit styles

So your charts look and behave as expected, you should import the IoT AppKit styles in one of your application components.

import '@iot-app-kit/components/styles.css';

Setting your AWS credentials

The dashboard application will access resources in your AWS account. Update the __FILL_IN__ placeholder values specific to your AWS account credentials.

const AWS_CREDENTIALS_ACCESS_KEY_ID: string = '__FILL_IN__';
const AWS_CREDENTIALS_SECRET_ACCESS_KEY: string = '__FILL_IN__';
const AWS_CREDENTIALS_SESSION_TOKEN: string = '__FILL_IN__';
const AWS_CREDENTIALS_EXPIRATION_IN_MS: number = __FILL_IN__;
const AWS_REGION: string = '__FILL_IN__';

Setting your TwinMaker workspace name

The dashboard application will use resources created for the Cookie Factory v2 demo. Update the __FILL_IN__ placeholder value with the name of the TwinMaker workspace you created when deploying the demo.

const AWS_IOT_TWINMAKER_WORKSPACE_NAME: string = '__FILL_IN__';

Setting the time span for the dashboard

The dashboard application will query historical data for a 15-minute time range from live (now).

const VIEWPORT_TIME_SPAN_IN_MIN = 15;

IoT AppKit components accept a DurationViewport for setting a time span, but in milliseconds. Convert VIEWPORT_TIME_SPAN_IN_MIN to milliseconds and set the viewport duration property.

To learn more about the IoT AppKit viewport and how to use it, visit the IoT AppKit documentation.

const VIEWPORT: DurationViewport = { duration: VIEWPORT_TIME_SPAN_IN_MIN * 60 * 1000 };

Creating styles for the alarm visualization

The IoT AppKit Threshold allows you to optionally style the StatusTimeline visualization based on a property's latest value. For the dashboard application, if the AlarmMessage property value is "High," data block will be red. If the value is "Medium," the data block will be dark orange. And so forth as shown below.

To learn more about IoT AppKit thresholds and how to use them, visit the IoT AppKit documentation.

const THRESHOLDS: Threshold<'High' | 'Medium' | 'Low' | 'Normal'>[] = [
  {
    color: 'red',
    value: 'High',
    comparisonOperator: 'EQ',
  },
  {
    color: 'darkorange',
    value: 'Medium',
    comparisonOperator: 'EQ',
  },
  {
    color: 'gold',
    value: 'Low',
    comparisonOperator: 'EQ',
  },
  {
    color: 'darkgreen',
    value: 'Normal',
    comparisonOperator: 'EQ',
  },
];

Creating styles for the data visualizations

The IoT AppKit StyleSettingsMap allows you to optionally style visualization components. For the dashboard application, the Temperature property line chart plot will be teal, and the Speed property line chart plot will be purple.

To learn more about styling IoT AppKit components and how to use StyleSettingsMap, visit the IoT AppKit documentation.

const LINE_CHART_STYLES: StyleSettingsMap = {
  ['Temperature']: { color: 'teal' },
  ['Speed']: { color: 'purple' },
};

Initializing the TwinMaker data source

Before you can query data from TwinMaker, you must initialize the IoT AppKit TwinMaker data source.

To learn more about the TwinMaker data source and how to use it, visit the IoT AppKit documentation.

import { initialize } from '@iot-app-kit/source-iottwinmaker';

const { query } = initialize(AWS_IOT_TWINMAKER_WORKSPACE_NAME, {
  awsCredentials: {
    accessKeyId: AWS_CREDENTIALS_ACCESS_KEY_ID,
    expiration: new Date(AWS_CREDENTIALS_EXPIRATION_IN_MS),
    secretAccessKey: AWS_CREDENTIALS_SECRET_ACCESS_KEY,
    sessionToken: AWS_CREDENTIALS_SESSION_TOKEN,
  },
  awsRegion: AWS_REGION,
});

Creating the TwinMaker queries

To query data from TwinMaker using IoT AppKit, you create TwinMaker entity history queries (TwinMakerEntityHistoryQuery) for the entities and properties of interest. From those history queries, you generate time series queries (TimeSeriesDataQuery) IoT AppKit components will actually use to fetch data.

For the dashboard application, create the entity history query for the Freezer Tunnel entity properties AlarmMessage, Temperature, and Speed as defined on the CookieLineComponent component.

const baseHistoryQuery: TwinMakerEntityHistoryQuery = {
  componentName: 'CookieLineComponent',
  entityId: 'FREEZER_TUNNEL_e12e0733-f5df-4604-8f10-417f49e6d298',
  properties: [],
};

const alarmHistoryQuery: TwinMakerEntityHistoryQuery = {
  ...baseHistoryQuery,
  properties: [
    {
      propertyName: 'AlarmMessage',
      refId: 'AlarmMessage',
    },
  ],
};

const dataHistoryQueries: TwinMakerEntityHistoryQuery[] = [
  {
    ...baseHistoryQuery,
    properties: [
      {
        propertyName: 'Temperature',
        refId: 'Temperature',
      },
    ],
  },
  {
    ...baseHistoryQuery,
    properties: [
      {
        propertyName: 'Speed',
        refId: 'Speed',
      },
    ],
  },
];

Next, generate the time series query for the alarm property AlarmMessage. Pass alarmHistoryQuery to the query module's timeSeriesData.

const alarmTimeSeriesQuery = query.timeSeriesData(alarmHistoryQuery);

Finally, generate the time series queries for the data properties Temperature and Speed. So you can visualize each property on its own chart, map over dataHistoryQueries and generate a time series query for each.

const dataTimeSeriesQueries = dataHistoryQueries.map((dataHistoryQuery) => {
  return query.timeSeriesData(dataHistoryQuery);
});

Putting it all together

Let's build the Cookie Factory dashboard application! Using your React starter project:

1. Install the IoT AppKit dependencies

npm install -S @iot-app-kit/react-components @iot-app-kit/source-iottwinmaker

2. Create a CSS file

CSS styles transform your HTML code into a layout that looks like a dashboard.

Create the file.

touch src/styles.css

Open src/styles.css, paste the following CSS code, and save the file.

* {
  box-sizing: border-box;
}

/* Element selectors */

body {
  display: flex;
  min-height: 100vh;
  padding: 15px 30px 30px;
  background-color: #e6e6e7;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
    'Helvetica Neue', sans-serif;
  color: #445;
}

h1 {
  margin: 0;
  font-weight: 300;
}

h2 {
  margin: 0;
  font-weight: 400;
}

h3 {
  margin: 0;
  font-weight: 500;
}

/* Id selectors */

#app {
  flex: 1;
  display: flex;
  flex-direction: column;
  row-gap: 15px;
}

/* Class selectors */

.card {
  display: flex;
  flex-direction: column;
  padding: 17px 30px 30px;
  background-color: white;
  border-radius: 10px;
  box-shadow: 0 0 10px rgb(0, 0, 0, 0.2);
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.charts {
  display: flex;
  flex-direction: column;
  width: 100%;
  margin-top: 15px;
  padding-top: 15px;
  border-top: solid 1px #e6e6e6;
}

/* Set a size on the chart container so that the IoT AppKit component sizes itself accordingly */
.charts .chart {
  width: 100%;
  height: 260px;
}

.charts .alarm {
  height: 200px;
}

3. Edit the application entry-point file

Open src/index.tsx, delete the existing code, paste the following React code, and save the file.

NOTE: You must update the __FILL_IN__ placeholder values with your AWS account credentials and TwinMaker workspace name.

import { createRoot } from 'react-dom/client';

// IoTAppkit required modules
import type { DurationViewport, StyleSettingsMap, Threshold } from '@iot-app-kit/core';
import { LineChart, StatusTimeline, TimeSync, WebglContext } from '@iot-app-kit/react-components';
import { initialize, type TwinMakerEntityHistoryQuery } from '@iot-app-kit/source-iottwinmaker';

// IoTAppkit styles
import '@iot-app-kit/components/styles.css';

// The dashbaord styles
import './styles.css';

// Your AWS account credentials
const AWS_CREDENTIALS_ACCESS_KEY_ID: string = '__FILL_IN__';
const AWS_CREDENTIALS_SECRET_ACCESS_KEY: string = '__FILL_IN__';
const AWS_CREDENTIALS_SESSION_TOKEN: string = '__FILL_IN__';
const AWS_CREDENTIALS_EXPIRATION_IN_MS: number = __FILL_IN__;
const AWS_REGION: string = '__FILL_IN__';

// Your TwinMaker workspace name
const AWS_IOT_TWINMAKER_WORKSPACE_NAME: string = '__FILL_IN__';

// The dashbaord time span from live
const VIEWPORT_TIME_SPAN_IN_MIN = 15;
const VIEWPORT: DurationViewport = { duration: VIEWPORT_TIME_SPAN_IN_MIN * 60 * 1000 };

// StatusTimeline styles
const THRESHOLDS: Threshold<'High' | 'Medium' | 'Low' | 'Normal'>[] = [
  {
    color: 'red',
    value: 'High',
    comparisonOperator: 'EQ',
  },
  {
    color: 'darkorange',
    value: 'Medium',
    comparisonOperator: 'EQ',
  },
  {
    color: 'gold',
    value: 'Low',
    comparisonOperator: 'EQ',
  },
  {
    color: 'darkgreen',
    value: 'Normal',
    comparisonOperator: 'EQ',
  },
];

// LineChart styles
const LINE_CHART_STYLES: StyleSettingsMap = {
  ['Temperature']: { color: 'teal' },
  ['Speed']: { color: 'purple' },
};

const { query } = initialize(AWS_IOT_TWINMAKER_WORKSPACE_NAME, {
  awsCredentials: {
    accessKeyId: AWS_CREDENTIALS_ACCESS_KEY_ID,
    expiration: new Date(AWS_CREDENTIALS_EXPIRATION_IN_MS),
    secretAccessKey: AWS_CREDENTIALS_SECRET_ACCESS_KEY,
    sessionToken: AWS_CREDENTIALS_SESSION_TOKEN,
  },
  awsRegion: AWS_REGION,
});

const baseHistoryQuery: TwinMakerEntityHistoryQuery = {
  componentName: 'CookieLineComponent',
  entityId: 'FREEZER_TUNNEL_e12e0733-f5df-4604-8f10-417f49e6d298',
  properties: [],
};

const alarmHistoryQuery: TwinMakerEntityHistoryQuery = {
  ...baseHistoryQuery,
  properties: [
    {
      propertyName: 'AlarmMessage',
      refId: 'AlarmMessage',
    },
  ],
};

const dataHistoryQueries: TwinMakerEntityHistoryQuery[] = [
  {
    ...baseHistoryQuery,
    properties: [
      {
        propertyName: 'Temperature',
        refId: 'Temperature',
      },
    ],
  },
  {
    ...baseHistoryQuery,
    properties: [
      {
        propertyName: 'Speed',
        refId: 'Speed',
      },
    ],
  },
];

// Alarm times series query
const alarmTimeSeriesQuery = query.timeSeriesData(alarmHistoryQuery);

// Data times series queries
const dataTimeSeriesQueries = dataHistoryQueries.map((dataHistoryQuery) => {
  return query.timeSeriesData(dataHistoryQuery);
});

const element = document.getElementById('app');

if (element) {
  createRoot(element).render(<App />);
}

function App() {
  // Map over the `dataTimeSeriesQueries` to create the line charts
  const lineCharts = dataTimeSeriesQueries.map((timeSeriesQuery) => {
    return (
      // Make sure to set a unique key for each element, in this case using the unique query string
      <div className="chart" key={timeSeriesQuery.toQueryString()}>
        <LineChart queries={[timeSeriesQuery]} viewport={VIEWPORT} styles={LINE_CHART_STYLES} />
      </div>
    );
  });

  return (
    <>
      <h2>Cookie Factory Monitor</h2>
      <section className="card">
        <section className="header">
          <h1>Freezer Tunnel Dashboard</h1>
          <span>Last {VIEWPORT_TIME_SPAN_IN_MIN} minutes</span>
        </section>
        <section className="charts">
          {/* Use the `TimeSync` provider to synchronize the current
              viewport time range across all charts */}
          <TimeSync initialViewport={VIEWPORT}>
            <h3>Alarm status</h3>
            <div className="chart alarm">
              <StatusTimeline queries={[alarmTimeSeriesQuery]} thresholds={THRESHOLDS} />
            </div>
            <h3>Property data</h3>
            {lineCharts}
          </TimeSync>
        </section>
      </section>
      <WebglContext />
    </>
  );
}

4. Start your development server

npm run dev

5. Test your application

Navigate to https://localhost:8080. Your application should look similar to this view.

iot-dashboard

Clone this wiki locally