Solution components
Web interface
The Virtual Andon on AWS solution features a web interface that simplifies managing factory settings, notifications, and data analysis. The interface leverages Amazon Cognito for user authentication, AWS Amplify for interacting with cloud services, and an Amazon Simple Storage Service (Amazon S3) bucket to host web assets.

Figure 2: Virtual Andon on AWS web interface
As shown in Figure 2, the web interface provides the following menu options: Sites, Client, Observer, Issues Reporting, Users, Permissions, and Root Causes. These options provide users with the following features:
-
Management tools: These tools include the Sites, Users, Permissions, and Root Causes menu options. Administrators use these tools to manage users (such as factory floor workers, engineers, and managers), assign them to one or more specialized groups (refer to Amazon Cognito user groups), and enter the factory details for their facility. Administrators use the Sites option to define a factory using the following criteria: sites, areas, processes, stations, devices, and event details.
-
Analysis tools: Users assigned to the Admin and Manager groups have access to the Issues Reporting tab. Users can view the historical information about issues that have occurred.
-
Client tool: This tool is provided in the Client menu option. Users identify events or issues on the factory floor using this tool. If a point-of-contact (such as an engineer) is assigned to the event, an Amazon Simple Notification Service (Amazon SNS) notification is sent.
-
Observer function: This function is provided in the Observer menu option. Users assigned to the Admin, Manager, and Engineer groups can access a real-time view of events across the factory site and respond to issues. Responses are recorded and synchronized in the web interface.
In order to access the web interface, the solution administrator must add users and assign them to one or more groups. Groups provide the users with the appropriate access privileges to the tools and functionalities available in the web interface. For details about setting up the web interface, refer to Automated deployment. For more information about the web interface, refer to Solution web interface.
The web interface supports the following languages: German, English, Spanish, French, Japanese, Korean, and simplified Chinese.
Data Analysis
Events and issues recorded and stored in this solution can be
exported from DynamoDB to an Amazon S3 bucket for in-depth
analysis and visualization in Amazon Athena,
Amazon QuickSight, or your own BI tool. To do this, set the
Activate Glue Workflow
parameter to Yes
when you deploy the CloudFormation template. For
more information, refer to
AWS Glue data export.
By default, the AWS Glue workflow that performs the data extract runs every Monday at 1:00 AM UTC.
AWS AppSync
The solution uses AWS AppSync queries, mutations, and subscriptions generated by the AppSync schema. These queries, mutations, and subscriptions help set up the factory with management tools and real-time issue updates.
External integrations
Amazon Lookout for Equipment
This solution can integrate with
Amazon
Lookout for Equipment
If integrating Lookout for Equipment, you can create an automated event in the solution’s web interface. Refer to Configure Amazon Lookout for Equipment for more information.
IoT devices
This solution uses AWS IoT Core, allowing you to configure your IoT devices to send data
to the solution’s ava/devices
IoT Core topic. To do this, the IoT device names
must be created in the solution and contain the necessary Event tag and corresponding values. For guidance to set up your IoT devices,
refer to Configure IoT devices.
Other Systems
The Virtual Andon on AWS solution allows data to be easily integrated from other
systems. To create issues in the solution originating from other devices, post a message to
the ava/issues
AWS IoT Core topic in the following format:
{ "id":
<ID!>
, "eventId": String, "eventDescription": String, "type": String, "priority": String, "siteName": String, "processName": String, "areaName":" String, "stationName": String, "deviceName": String, "created": AWSDateTime, "acknowledged": AWSDateTime, "closed": AWSDateTime, "status": "open" }
Set up the siteName
,
processName
, areaName
, stationName
, deviceName
, and
eventDescription
from the management UI before sending data to
this topic. This ensures consistency across the observer UI and
provides accurate information to engineers.
If you need support connecting to industrial equipment, refer to the Machine to Cloud
Connectivity Frameworkava/issues
topic.
The format can also be used to call the createIssue
AppSync mutation
directly using an AWS AppSync client. For more information about building a NodeJS AppSync
client, refer to Create a Client Application in the AWS AppSync Developer Guide or
refer to the source codeHandleIssues
AWS Lambda function. To use the
AppSync API with an AppSync client, your AWS Identity and Access Management (IAM) role must have the necessary
permissions to perform the desired AppSync queries and mutations.
API
This solution uses
AWS AppSyncGraphQLEndpoint
, which allows you to
send HTTP POST requests to interact with the GraphQL API. This
endpoint is created by AWS AppSync. You can identify this
endpoint after the stack is created by navigating to the
Outputs tab and locating the
value of the GraphQLEndpoint
.
When using this API, you must sign AWS requests with Signature
Version 4. For more information, refer to
Signing
AWS requests with Signature Version 4 in the
AWS General Reference Guide. This process
generates the values needed for the X-Amz-Content-Sha256
,
X-Amz-Date
, and Authorization
headers.
Two Issue Management API mutations available in the solution’s
APIs are provided: createIssue
and updateIssue
. A comprehensive
list of queries and mutations for this solution’s API is
available from the AWS AppSync console. From the APIs page,
select ava-api
and a list of the solution’s APIs is displayed on
the Schema page. For more
information about the AWS AppSync GraphQL, refer to
GraphQL
Overview in the AWS AppSync Developer
Guide.

Figure 3: Solution APIs listed on AWS AppSync
When sending API
requests as an IAM user, this user must have the
IAM
permissions to perform AWS AppSync actions for that API.
Additionally, the specific queries and mutations in the AWS AppSync schema must have @aws_iam
as an authorization option for
that action.
Issue Management APIs
- createIssue
-
Creates a new Issue with the supplied Event and Site Hierarchy details.
Request syntax:
POST /graphql HTTP/1.1 Host:
<VALUE>
X-Amz-Content-Sha256:<VALUE>
X-Amz-Date:<VALUE>
Authorization:<VALUE>
Content-Type: application/json Content-Length:<VALUE>
mutation SampleCreateIssue { createIssue( input: { id: “<string>
”, siteName: “<string>
”, areaName: “<string>
”, stationName: “<string>
”, deviceName: “<string>
”, processName: “<string>
”, eventId: “<string>
”, eventDescription: “<string>
”, eventType: “<string>
”, issueSource: “<string>
”, priority: “<string>
”, status: “<string>
”, created: “AWSDateTime”, acknowledged: “AWSDateTime”, closed: “AWSDateTime”, acknowledgedTime: “<number>
”, resolutionTime: “<number>
”, createdBy: “<string>
”, additionalDetails: “<string>
” } ) { id }, variables: {} }Request body:
id
The ID of the new issue to be created. If an ID is not supplied, a 128-bit randomly generated UUID will be used.
Type: String
Required: No
- siteName
-
The name of the site for which this issue will be created.
Type: String
Required: Yes
- areaName
-
The name of the area for which this issue will be created.
Type: String
Required: Yes
- stationName
-
The name of the station for which this issue will be created.
Type: String
Required: Yes
- deviceName
-
The name of the Device for which this issue will be created.
Type: string
Required: Yes
- processName
-
The name of the process for which this issue will be created.
Type: String
Required: Yes
- eventId
-
The event ID for an issue.
Type: String
Required: Yes
- eventDescription
-
The description for an event where there is an issue.
Type: String
Required: Yes
- eventType
-
The type of the event where there is an issue.
Type: String
Required: No
- issueSource
-
The source of the issue; values include:
webClient
,s3File
, anddevice
.Type: String
Required: Yes
- priority
-
The event priority for this issue; values include:
low
,medium
,high
, andcritical
.Type: String
Required: Yes
- status
-
Status of the issue; values include:
open
,acknowledged
,closed
,inprogress
, andrejected
.Type: String
Required: Yes
- created
-
Timestamp for when this issue was created, in
AWSDateTime
format.Type: String
Required: Yes
- acknowledged
-
Timestamp for when this issue was acknowledged, in
AWSDateTime
format.Type: String
Required: No
- closed
-
Timestamp for when this issue was closed, in
AWSDateTime
format.Type: String
Required: No
- acknowledgedTime
-
The number of seconds the issue was active before being acknowledged.
Type: Number
Required: No
- resolutionTime
-
The number of seconds the issue was active before being resolved.
Type: Number
Required: No
- createdBy
Identifier (such as the email address) of the person or entity creating the issue.
Type: String
Required: Yes
- additionalDetails
-
JSON string providing additional details about the issue, such as anomaly details for issues raised from processing Amazon Lookout for Equipment results.
Type: String
Required: No
Response syntax:
HTTP/1.1 200 { data: { createIssue: { id: “
<string>
” } } }Response elements:
- id
-
The ID of the new issue.
Type: String
- updateIssue
-
Updates an existing Issue with the supplied properties.
Request syntax:
POST /graphql HTTP/1.1 Host:
<VALUE>
X-Amz-Content-Sha256:<VALUE>
X-Amz-Date:<VALUE>
Authorization:<VALUE>
Content-Type: application/json Content-Length:<VALUE>
mutation SampleUpdateIssue { updateIssue( input: { id: “<string>
”, siteName: “<string>
”, areaName: “<string>
”, stationName: “<string>
”, deviceName: “<string>
”, processName: “<string>
”, eventId: “<string>
”, eventDescription: “<string>
”, eventType: “<string>
”, issueSource: “<string>
”, priority: “<string>
”, status: “<string>
”, created: “AWSDateTime”, createdAt: “AWSDateTime”, acknowledged: “AWSDateTime”, closed: “AWSDateTime”, acknowledgedTime: “<number>
”, resolutionTime: “<number>
”, createdBy: “<string>
”, closedBy: “<string>
”, rejectedBy: “<string>
”, acknowledgedBy: “<string>
”, additionalDetails: “<string>
”, expectedVersion: “<number>
”, rootCause: “<string>
”, comment: “<string>
” } ) { id status }, variables: {} }Request body:
id
The ID of the new issue to be created.
Type: String
Required: No
- siteName
-
The name of the site where this issue is created.
Type: String
Required: No
- areaName
-
The name of the area where this issue is created.
Type: String
Required: No
- stationName
-
The name of the station where this issue is created.
Type: String
Required: No
- deviceName
-
The name of the device where this issue is created.
Type: String
Required: No
- processName
-
The name of the process where this issue is created.
Type: String
Required: No
- eventId
-
The ID of the event where there is an issue.
Type: String
Required: Yes
- eventDescription
-
The description of the event where there is an issue.
Type: String
Required: No
- eventType
-
The type of the event where there is an issue.
Type: String
Required: No
- issueSource
-
Source for the issue; values include:
webClient
,s3File
, anddevice
.Type: String
Required: Yes
- priority
-
The event priority for this issue; values include:
low
,medium
,high
, andcritical
.Type: String
Required: No
- status
-
Status of the issue; values include:
open
,acknowledged
,closed
,inprogress
, andrejected
.Type: String
Required: Yes
- created
-
Timestamp for when this issue was created, in
AWSDateTime
format.Type: String
Required: No
- createdAt
-
UTC timestamp for when this issue was created, in
AWSDateTime
format.Type: String
Required: No
- acknowledged
-
Timestamp for when this issue was acknowledged, in
AWSDateTime
format.Type: String
Required: No
- closed
-
Timestamp for when this issue was closed, in
AWSDateTime
format.Type: String
Required: No
- acknowledgedTime
-
The number of seconds the issue was active before being acknowledged.
Type: Number
Required: No
- resolutionTime
-
The number of seconds the issue was active before being resolved.
Type: Number
Required: No
- createdBy
-
The identifier (such as an email address) of the person or entity creating the issue.
Type: String
Required: No
- closedBy
-
The identifier (such as an email address) of the person or entity closing the issue.
Type: String
Required: No
- rejectedBy
-
The identifier (such as an email address) of the person or entity rejecting the issue.
Type: String
Required: No
- acknowledgedBy
-
Identifier (i.e., email address) of the person or entity acknowledging the issue.
Type: String
Required: No
- additionalDetails
-
JSON string with providing additional details about the issue, such as anomaly details for issues raised from processing Amazon Lookout for Equipment results.
Type: String
Required: No
- expectedVersion
-
The version of the Issue that is being updated. If this version does not match the latest version, the update will fail.
Type: Number
Required: Yes
- rootCause
-
When closing an issue, the name of the root cause for this issue.
Type: String
Required: No
- comment
-
When closing an issue with a root cause, provides additional details about what caused the issue.
Type: String
Required: No
- Response syntax:
-
HTTP/1.1 200 { data: { updateIssue: { id: “
<string>
”, status: “<string>
” } } }Response elements:
- id
-
The ID of the updated issue.
Type: String
- status
-
The new status of the issue.
Type: String
Amazon Cognito user groups
The solution uses Amazon Cognito to authenticate users. Authorization to the different user interface components is restricted by the user’s assigned group. As shown in Figure 4, the solution administrator assigns a user to one of the following groups:
-
Admin Group: Users in this group have access to all menu options, providing them with access to the management, analysis, and client tools, as well as the Observer function.
-
Manager Group: Users in this group can access the Client, Observer, and Issues Reporting menu options, providing them with access to the analysis and client tools and the Observer function.
-
Engineer Group: Users in this group can access the Client and Observer options.
-
Associate Group: Users in this group can access the Client option.

Figure 4: Web interface Add User page
As an administrator you can restrict a user's access to certain sites, processes, and
areas so that only information related to the assigned group can be viewed. The solution
administrator manages this access through Amazon Cognito user groups to the AWS AppSync
GraphQL queries and mutations. Users that are not in the appropriate resolver group
cannot query the AWS AppSync schema. For example, the following schema shows a
schema.graphql
file where only users assigned to the Admin Group have access to the mutations that allow a site to be deleted
(deleteSite
).
type Mutation { deleteSite(id: ID!): Site @aws_auth(cognito_groups: ["AdminGroup"]) }
If the user calling the deleteSite
mutation is not in the
AdminGroup
, an error will be returned and the request will be
blocked. The following code is from mutation.delete.req.vtl
, the
Velocity Template Language (VTL) code that performs the deleteSite
request. The authorization is checked at the top and if the user
is not in the AdminGroup
, the unauthorized()
utility
function is used to block the request.
## Check authorization #set ($isAllowed = false) #set ($userGroups = $ctx.identity.claims.get("cognito:groups")) #set ($allowedGroups = ["AdminGroup"]) #foreach ($userGroup in $userGroups) #if ($allowedGroups.contains($userGroup)) #set ($isAllowed = true) #break #end #end ## Throw authorized if the user is not authorized. #if ($isAllowed == false) $util.unauthorized() #end { "version": "2017-02-28", "operation": "DeleteItem", "key": { "id": $util.dynamodb.toDynamoDBJson($ctx.args.id) } }
Amazon DynamoDB
This solution uses Amazon DynamoDB to persist factory setup data and store user generated issues. This solution creates the following DynamoDB tables:
-
Data Hierarchy: Stores information related to a factory’s layout (Sites, Areas, Processes, etc.) as well as user Permissions and Root Causes.
-
Issue: Stores metadata about the issues that are activated by users.
AWS IoT Core
The web interface communicates with AWS IoT Core to publish messages regarding the
issues occurring on the factory floor to an AWS IoT Core topic. Specifically, the web
interface uses the AWS Amplify
PubSub
categoryAWSIoTProvider
, which signs a
request according to Signature Version 4. The AWS IoT
Core rules engine invokes an AWS Lambda function that processes the message.
The solution creates an AWS IoT Core policy during deployment. When a user accesses the
web interface, the appropriate AWS IoT Core policy is assigned an Amazon Cognito
identity based on the group that the user belongs to. This policy allows the user to
post to the ava/issues
and ava/groups/#
AWS IoT topics.
Solution microservices
The Virtual Andon on AWS microservices are a series of AWS Lambda functions that provide
the business logic and data access layer for all device operations. Each Lambda function
assumes an AWS Identity and Access Management
AWS AppSync Lambda resolver microservice
The AppSyncLambdaResolver
microservice is used when complex
logic is involved in the processing of an AWS AppSync mutation.
An AWS Lambda function is invoked to process either the entire
mutation or a certain component of it. For example, when
creating or updating an event, this microservice is used to
manage changes to the solution’s IssueNotification
Amazon SNS
topic after the event has been updated directly with a
velocity
template language (VTL) template.
Handle issues microservice
The HandleIssues
microservice runs every time a message is posted to
the ava/issues
topic in AWS IoT Core or a file is placed in the DetectedAnomalies
Amazon S3 bucket. This microservice calls the AWS AppSync API to store the
issue details in the issue
Amazon DynamoDB table, and sends a notification to the
Amazon Simple Notification Service (Amazon SNS) topic for the event.
Amazon Cognito trigger microservice
This microservice is used only when you have configured a SAML identity provider. To assist with managing users that have logged into the solution’s web interface using a SAML identity provider, a Post Confirmation Lambda Trigger invokes this microservice to run custom actions for these users. By default, this Lambda function logs only that a user has been created using the Federated SAML access. This function can be extended by choosing to either automatically add users to specific Amazon Cognito user groups or by setting default permissions in the solution. Existing user management capabilities in the web interface exist for federated SAML users if you prefer to manually configure groups and permissions for these users.
Solution helper microservice
The SolutionHelper
microservice supports the initial solution setup, which
includes putting the solution’s web interface resources and configuration into an Amazon Simple Storage Service
(Amazon S3) bucket. This microservice also updates the solution when customers deploy a new
version of the solution.
External integrations microservice
The ExternalIntegrations
microservice is an entry point for
external systems to create issues in Virtual Andon on AWS. For
example, if IoT devices send messages directly to the
ava/devices
IoT Core topic, this microservice is invoked.
Similarly, if you are using Amazon Lookout for Equipment and
supply the name of the Amazon S3 bucket where anomaly files will
be delivered, this microservice is invoked whenever an anomaly
file is added to the bucket. After performing validation, this
microservice publishes a message to the ava/issues
IoT Core
topic where the HandleIssues
microservice creates the issue.