AWS IoT SiteWise examples using SDK for JavaScript (v3) (original) (raw)
import {
Scenario,
ScenarioAction,
ScenarioInput,
ScenarioOutput,
//} from "@aws-doc-sdk-examples/lib/scenario/index.js";
} from "../../libs/scenario/index.js";
import {
IoTSiteWiseClient,
CreateAssetModelCommand,
CreateAssetCommand,
ListAssetModelPropertiesCommand,
BatchPutAssetPropertyValueCommand,
GetAssetPropertyValueCommand,
CreatePortalCommand,
DescribePortalCommand,
CreateGatewayCommand,
DescribeGatewayCommand,
DeletePortalCommand,
DeleteGatewayCommand,
DeleteAssetCommand,
DeleteAssetModelCommand,
DescribeAssetModelCommand,
} from "@aws-sdk/client-iotsitewise";
import {
CloudFormationClient,
CreateStackCommand,
DeleteStackCommand,
DescribeStacksCommand,
waitUntilStackExists,
waitUntilStackCreateComplete,
waitUntilStackDeleteComplete,
} from "@aws-sdk/client-cloudformation";
import { wait } from "@aws-doc-sdk-examples/lib/utils/util-timers.js";
import { parseArgs } from "node:util";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const stackName = "SiteWiseBasicsStack";
/**
* @typedef {{
* iotSiteWiseClient: import('@aws-sdk/client-iotsitewise').IotSiteWiseClient,
* cloudFormationClient: import('@aws-sdk/client-cloudformation').CloudFormationClient,
* stackName,
* stack,
* askToDeleteResources: true,
* asset: {assetName: "MyAsset1"},
* assetModel: {assetModelName: "MyAssetModel1"},
* portal: {portalName: "MyPortal1"},
* gateway: {gatewayName: "MyGateway1"},
* propertyIds: [],
* contactEmail: "user@mydomain.com",
* thing: "MyThing1",
* sampleData: { temperature: 23.5, humidity: 65.0}
* }} State
*/
/**
* Used repeatedly to have the user press enter.
* @type {ScenarioInput}
*/
const pressEnter = new ScenarioInput("continue", "Press Enter to continue", {
type: "confirm",
});
const greet = new ScenarioOutput(
"greet",
`AWS IoT SiteWise is a fully managed industrial software-as-a-service (SaaS) that makes it easy to collect, store, organize, and monitor data from industrial equipment and processes. It is designed to help industrial and manufacturing organizations collect data from their equipment and processes, and use that data to make informed decisions about their operations.
One of the key features of AWS IoT SiteWise is its ability to connect to a wide range of industrial equipment and systems, including programmable logic controllers (PLCs), sensors, and other industrial devices. It can collect data from these devices and organize it into a unified data model, making it easier to analyze and gain insights from the data. AWS IoT SiteWise also provides tools for visualizing the data, setting up alarms and alerts, and generating reports.
Another key feature of AWS IoT SiteWise is its ability to scale to handle large volumes of data. It can collect and store data from thousands of devices and process millions of data points per second, making it suitable for large-scale industrial operations. Additionally, AWS IoT SiteWise is designed to be secure and compliant, with features like role-based access controls, data encryption, and integration with other AWS services for additional security and compliance features.
Let's get started...`,
{ header: true },
);
const displayBuildCloudFormationStack = new ScenarioOutput(
"displayBuildCloudFormationStack",
"This scenario uses AWS CloudFormation to create an IAM role that is required for this scenario. The stack will now be deployed.",
);
const sdkBuildCloudFormationStack = new ScenarioAction(
"sdkBuildCloudFormationStack",
async (/** @type {State} */ state) => {
try {
const data = readFileSync(
`${__dirname}/../../../../resources/cfn/iotsitewise_basics/SitewiseRoles-template.yml`,
"utf8",
);
await state.cloudFormationClient.send(
new CreateStackCommand({
StackName: stackName,
TemplateBody: data,
Capabilities: ["CAPABILITY_IAM"],
}),
);
await waitUntilStackExists(
{ client: state.cloudFormationClient },
{ StackName: stackName },
);
await waitUntilStackCreateComplete(
{ client: state.cloudFormationClient },
{ StackName: stackName },
);
const stack = await state.cloudFormationClient.send(
new DescribeStacksCommand({
StackName: stackName,
}),
);
state.stack = stack.Stacks[0].Outputs[0];
console.log(`The ARN of the IAM role is ${state.stack.OutputValue}`);
} catch (caught) {
console.error(caught.message);
throw caught;
}
},
);
const displayCreateAWSSiteWiseAssetModel = new ScenarioOutput(
"displayCreateAWSSiteWiseAssetModel",
`1. Create an AWS SiteWise Asset Model
An AWS IoT SiteWise Asset Model is a way to represent the physical assets, such as equipment, processes, and systems, that exist in an industrial environment. This model provides a structured and hierarchical representation of these assets, allowing users to define the relationships and properties of each asset.
This scenario creates two asset model properties: temperature and humidity.`,
);
const sdkCreateAWSSiteWiseAssetModel = new ScenarioAction(
"sdkCreateAWSSiteWiseAssetModel",
async (/** @type {State} */ state) => {
let assetModelResponse;
try {
assetModelResponse = await state.iotSiteWiseClient.send(
new CreateAssetModelCommand({
assetModelName: state.assetModel.assetModelName,
assetModelProperties: [
{
name: "Temperature",
dataType: "DOUBLE",
type: {
measurement: {},
},
},
{
name: "Humidity",
dataType: "DOUBLE",
type: {
measurement: {},
},
},
],
}),
);
state.assetModel.assetModelId = assetModelResponse.assetModelId;
console.log(
`Asset Model successfully created. Asset Model ID: ${state.assetModel.assetModelId}`,
);
} catch (caught) {
if (caught.name === "ResourceAlreadyExistsException") {
console.log(
`The Asset Model ${state.assetModel.assetModelName} already exists.`,
);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displayCreateAWSIoTSiteWiseAssetModel = new ScenarioOutput(
"displayCreateAWSIoTSiteWiseAssetModel",
`2. Create an AWS IoT SiteWise Asset
The IoT SiteWise model that we just created defines the structure and metadata for your physical assets. Now we create an asset from the asset model.
Let's wait 30 seconds for the asset to be ready.`,
);
const waitThirtySeconds = new ScenarioAction("waitThirtySeconds", async () => {
await wait(30); // wait 30 seconds
console.log("Time's up! Let's check the asset's status.");
});
const sdkCreateAWSIoTSiteWiseAssetModel = new ScenarioAction(
"sdkCreateAWSIoTSiteWiseAssetModel",
async (/** @type {State} */ state) => {
try {
const assetResponse = await state.iotSiteWiseClient.send(
new CreateAssetCommand({
assetModelId: state.assetModel.assetModelId,
assetName: state.asset.assetName,
}),
);
state.asset.assetId = assetResponse.assetId;
console.log(`Asset created with ID: ${state.asset.assetId}`);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(
`The Asset ${state.assetModel.assetModelName} was not found.`,
);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displayRetrievePropertyId = new ScenarioOutput(
"displayRetrievePropertyId",
`3. Retrieve the property ID values
To send data to an asset, we need to get the property ID values. In this scenario, we access the temperature and humidity property ID values.`,
);
const sdkRetrievePropertyId = new ScenarioAction(
"sdkRetrievePropertyId",
async (state) => {
try {
const retrieveResponse = await state.iotSiteWiseClient.send(
new ListAssetModelPropertiesCommand({
assetModelId: state.assetModel.assetModelId,
}),
);
for (const retrieveResponseKey in retrieveResponse.assetModelPropertySummaries) {
if (
retrieveResponse.assetModelPropertySummaries[retrieveResponseKey]
.name === "Humidity"
) {
state.propertyIds.Humidity =
retrieveResponse.assetModelPropertySummaries[
retrieveResponseKey
].id;
}
if (
retrieveResponse.assetModelPropertySummaries[retrieveResponseKey]
.name === "Temperature"
) {
state.propertyIds.Temperature =
retrieveResponse.assetModelPropertySummaries[
retrieveResponseKey
].id;
}
}
console.log(`The Humidity propertyId is ${state.propertyIds.Humidity}`);
console.log(
`The Temperature propertyId is ${state.propertyIds.Temperature}`,
);
} catch (caught) {
if (caught.name === "IoTSiteWiseException") {
console.log(
`There was a problem retrieving the properties: ${caught.message}`,
);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displaySendDataToIoTSiteWiseAsset = new ScenarioOutput(
"displaySendDataToIoTSiteWiseAsset",
`4. Send data to an AWS IoT SiteWise Asset
By sending data to an IoT SiteWise Asset, you can aggregate data from multiple sources, normalize the data into a standard format, and store it in a centralized location. This makes it easier to analyze and gain insights from the data.
In this example, we generate sample temperature and humidity data and send it to the AWS IoT SiteWise asset.`,
);
const sdkSendDataToIoTSiteWiseAsset = new ScenarioAction(
"sdkSendDataToIoTSiteWiseAsset",
async (state) => {
try {
const sendResponse = await state.iotSiteWiseClient.send(
new BatchPutAssetPropertyValueCommand({
entries: [
{
entryId: "entry-3",
assetId: state.asset.assetId,
propertyId: state.propertyIds.Humidity,
propertyValues: [
{
value: {
doubleValue: state.sampleData.humidity,
},
timestamp: {
timeInSeconds: Math.floor(Date.now() / 1000),
},
},
],
},
{
entryId: "entry-4",
assetId: state.asset.assetId,
propertyId: state.propertyIds.Temperature,
propertyValues: [
{
value: {
doubleValue: state.sampleData.temperature,
},
timestamp: {
timeInSeconds: Math.floor(Date.now() / 1000),
},
},
],
},
],
}),
);
console.log("The data was sent successfully.");
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(`The Asset ${state.asset.assetName} was not found.`);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displayRetrieveValueOfIoTSiteWiseAsset = new ScenarioOutput(
"displayRetrieveValueOfIoTSiteWiseAsset",
`5. Retrieve the value of the IoT SiteWise Asset property
IoT SiteWise is an AWS service that allows you to collect, process, and analyze industrial data from connected equipment and sensors. One of the key benefits of reading an IoT SiteWise property is the ability to gain valuable insights from your industrial data.`,
);
const sdkRetrieveValueOfIoTSiteWiseAsset = new ScenarioAction(
"sdkRetrieveValueOfIoTSiteWiseAsset",
async (/** @type {State} */ state) => {
try {
const temperatureResponse = await state.iotSiteWiseClient.send(
new GetAssetPropertyValueCommand({
assetId: state.asset.assetId,
propertyId: state.propertyIds.Temperature,
}),
);
const humidityResponse = await state.iotSiteWiseClient.send(
new GetAssetPropertyValueCommand({
assetId: state.asset.assetId,
propertyId: state.propertyIds.Humidity,
}),
);
console.log(
`The property value for Temperature is ${temperatureResponse.propertyValue.value.doubleValue}`,
);
console.log(
`The property value for Humidity is ${humidityResponse.propertyValue.value.doubleValue}`,
);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(`The Asset ${state.asset.assetName} was not found.`);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displayCreateIoTSiteWisePortal = new ScenarioOutput(
"displayCreateIoTSiteWisePortal",
`6. Create an IoT SiteWise Portal
An IoT SiteWise Portal allows you to aggregate data from multiple industrial sources, such as sensors, equipment, and control systems, into a centralized platform.`,
);
const sdkCreateIoTSiteWisePortal = new ScenarioAction(
"sdkCreateIoTSiteWisePortal",
async (/** @type {State} */ state) => {
try {
const createPortalResponse = await state.iotSiteWiseClient.send(
new CreatePortalCommand({
portalName: state.portal.portalName,
portalContactEmail: state.contactEmail,
roleArn: state.stack.OutputValue,
}),
);
state.portal = { ...state.portal, ...createPortalResponse };
await wait(5); // Allow the portal to properly propagate.
console.log(
`Portal created successfully. Portal ID ${createPortalResponse.portalId}`,
);
} catch (caught) {
if (caught.name === "IoTSiteWiseException") {
console.log(
`There was a problem creating the Portal: ${caught.message}.`,
);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displayDescribePortal = new ScenarioOutput(
"displayDescribePortal",
`7. Describe the Portal
In this step, we get a description of the portal and display the portal URL.`,
);
const sdkDescribePortal = new ScenarioAction(
"sdkDescribePortal",
async (/** @type {State} */ state) => {
try {
const describePortalResponse = await state.iotSiteWiseClient.send(
new DescribePortalCommand({
portalId: state.portal.portalId,
}),
);
console.log(`Portal URL: ${describePortalResponse.portalStartUrl}`);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(`The Portal ${state.portal.portalName} was not found.`);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displayCreateIoTSiteWiseGateway = new ScenarioOutput(
"displayCreateIoTSiteWiseGateway",
`8. Create an IoT SiteWise Gateway
IoT SiteWise Gateway serves as the bridge between industrial equipment, sensors, and the cloud-based IoT SiteWise service. It is responsible for securely collecting, processing, and transmitting data from various industrial assets to the IoT SiteWise platform, enabling real-time monitoring, analysis, and optimization of industrial operations.`,
);
const sdkCreateIoTSiteWiseGateway = new ScenarioAction(
"sdkCreateIoTSiteWiseGateway",
async (/** @type {State} */ state) => {
try {
const createGatewayResponse = await state.iotSiteWiseClient.send(
new CreateGatewayCommand({
gatewayName: state.gateway.gatewayName,
gatewayPlatform: {
greengrassV2: {
coreDeviceThingName: state.thing,
},
},
}),
);
console.log(
`Gateway creation completed successfully. ID is ${createGatewayResponse.gatewayId}`,
);
state.gateway.gatewayId = createGatewayResponse.gatewayId;
} catch (caught) {
if (caught.name === "IoTSiteWiseException") {
console.log(
`There was a problem creating the gateway: ${caught.message}.`,
);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const displayDescribeIoTSiteWiseGateway = new ScenarioOutput(
"displayDescribeIoTSiteWiseGateway",
"9. Describe the IoT SiteWise Gateway",
);
const sdkDescribeIoTSiteWiseGateway = new ScenarioAction(
"sdkDescribeIoTSiteWiseGateway",
async (/** @type {State} */ state) => {
try {
const describeGatewayResponse = await state.iotSiteWiseClient.send(
new DescribeGatewayCommand({
gatewayId: state.gateway.gatewayId,
}),
);
console.log("Gateway creation completed successfully.");
console.log(`Gateway Name: ${describeGatewayResponse.gatewayName}`);
console.log(`Gateway ARN: ${describeGatewayResponse.gatewayArn}`);
console.log(
`Gateway Platform: ${Object.keys(describeGatewayResponse.gatewayPlatform)}`,
);
console.log(
`Gateway Creation Date: ${describeGatewayResponse.creationDate}`,
);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(`The Gateway ${state.gateway.gatewayId} was not found.`);
throw caught;
}
console.error(`${caught.message}`);
throw caught;
}
},
);
const askToDeleteResources = new ScenarioInput(
"askToDeleteResources",
`10. Delete the AWS IoT SiteWise Assets
Before you can delete the Asset Model, you must delete the assets.`,
{ type: "confirm" },
);
const displayConfirmDeleteResources = new ScenarioAction(
"displayConfirmDeleteResources",
async (/** @type {State} */ state) => {
if (state.askToDeleteResources) {
return "You selected to delete the SiteWise assets.";
}
return "The resources will not be deleted. Please delete them manually to avoid charges.";
},
);
const sdkDeleteResources = new ScenarioAction(
"sdkDeleteResources",
async (/** @type {State} */ state) => {
await wait(10); // Give the portal status time to catch up.
try {
await state.iotSiteWiseClient.send(
new DeletePortalCommand({
portalId: state.portal.portalId,
}),
);
console.log(
`Portal ${state.portal.portalName} was deleted successfully.`,
);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(`The Portal ${state.portal.portalName} was not found.`);
} else {
console.log(`When trying to delete the portal: ${caught.message}`);
}
}
try {
await state.iotSiteWiseClient.send(
new DeleteGatewayCommand({
gatewayId: state.gateway.gatewayId,
}),
);
console.log(
`Gateway ${state.gateway.gatewayName} was deleted successfully.`,
);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(`The Gateway ${state.gateway.gatewayId} was not found.`);
} else {
console.log(`When trying to delete the gateway: ${caught.message}`);
}
}
try {
await state.iotSiteWiseClient.send(
new DeleteAssetCommand({
assetId: state.asset.assetId,
}),
);
await wait(5); // Allow the delete to finish.
console.log(`Asset ${state.asset.assetName} was deleted successfully.`);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(`The Asset ${state.asset.assetName} was not found.`);
} else {
console.log(`When deleting the asset: ${caught.message}`);
}
}
await wait(30); // Allow asset deletion to finish.
try {
await state.iotSiteWiseClient.send(
new DeleteAssetModelCommand({
assetModelId: state.assetModel.assetModelId,
}),
);
console.log(
`Asset Model ${state.assetModel.assetModelName} was deleted successfully.`,
);
} catch (caught) {
if (caught.name === "ResourceNotFoundException") {
console.log(
`The Asset Model ${state.assetModel.assetModelName} was not found.`,
);
} else {
console.log(`When deleting the asset model: ${caught.message}`);
}
}
try {
await state.cloudFormationClient.send(
new DeleteStackCommand({
StackName: stackName,
}),
);
await waitUntilStackDeleteComplete(
{ client: state.cloudFormationClient },
{ StackName: stackName },
);
console.log("The stack was deleted successfully.");
} catch (caught) {
console.log(
`${caught.message}. The stack was NOT deleted. Please clean up the resources manually.`,
);
}
},
{ skipWhen: (/** @type {{}} */ state) => !state.askToDeleteResources },
);
const goodbye = new ScenarioOutput(
"goodbye",
"This concludes the IoT Sitewise Basics scenario for the AWS Javascript SDK v3. Thank you!",
);
const myScenario = new Scenario(
"IoTSiteWise Basics",
[
greet,
pressEnter,
displayBuildCloudFormationStack,
sdkBuildCloudFormationStack,
pressEnter,
displayCreateAWSSiteWiseAssetModel,
sdkCreateAWSSiteWiseAssetModel,
displayCreateAWSIoTSiteWiseAssetModel,
pressEnter,
waitThirtySeconds,
sdkCreateAWSIoTSiteWiseAssetModel,
pressEnter,
displayRetrievePropertyId,
sdkRetrievePropertyId,
pressEnter,
displaySendDataToIoTSiteWiseAsset,
sdkSendDataToIoTSiteWiseAsset,
pressEnter,
displayRetrieveValueOfIoTSiteWiseAsset,
sdkRetrieveValueOfIoTSiteWiseAsset,
pressEnter,
displayCreateIoTSiteWisePortal,
sdkCreateIoTSiteWisePortal,
pressEnter,
displayDescribePortal,
sdkDescribePortal,
pressEnter,
displayCreateIoTSiteWiseGateway,
sdkCreateIoTSiteWiseGateway,
pressEnter,
displayDescribeIoTSiteWiseGateway,
sdkDescribeIoTSiteWiseGateway,
pressEnter,
askToDeleteResources,
displayConfirmDeleteResources,
sdkDeleteResources,
goodbye,
],
{
iotSiteWiseClient: new IoTSiteWiseClient({}),
cloudFormationClient: new CloudFormationClient({}),
asset: { assetName: "MyAsset1" },
assetModel: { assetModelName: "MyAssetModel1" },
portal: { portalName: "MyPortal1" },
gateway: { gatewayName: "MyGateway1" },
propertyIds: [],
contactEmail: "user@mydomain.com",
thing: "MyThing1",
sampleData: { temperature: 23.5, humidity: 65.0 },
},
);
/** @type {{ stepHandlerOptions: StepHandlerOptions }} */
export const main = async (stepHandlerOptions) => {
await myScenario.run(stepHandlerOptions);
};
// Invoke main function if this file was run directly.
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const { values } = parseArgs({
options: {
yes: {
type: "boolean",
short: "y",
},
},
});
main({ confirmAll: values.yes });
}