Skip to content

Mindconnect-NodeJS - Agent Development - Starter Projects

Introduction

The easiest way to start the development is to use the CLI to generate the starter projects

Prerequisites

You will need the installed CLI.

Step 1 - Create the project with help of the CLI

Example

Use the CLI to setup a starter project called my-agent:

mdsp createts --dir my-agent

This will provide following output:

Starter project in my-agent has been created.
Please run npm install in my-agent directory to install dependecies.
# after this we will install the required dependencies

cd my-agent
npm install

After this create the agentconfig.json with help of the CLI:

mdsp create-agent --passkey{your passkey} --config agentconfig.json

This will produce following output

Configure your agent at:

        https://{yourtenant}-assetmanager.eu1.mindsphere.io/entity/{agentid}/plugin/uipluginassetmanagermclib

Step 2 - Create the assets in Insights Hub

Create aspect types, asset type and asset in InsightsHub. Remember your asset id.

Step 3 - Configure the agent

You can use the new automatic creation of DataSourceConfiguration and DataSourceMappings to configure your agent.

import {
  DataPointValue,
  MindConnectAgent,
  MindSphereStandardEvent,
  retry,
  TimeStampedDataPoint,
} from "@mindconnect/mindconnect-nodejs";

(async function () {
  const sleep = (ms: any) => new Promise((resolve) => setTimeout(resolve, ms));
  const configuration = require("../../agentconfig.json");
  const agent = new MindConnectAgent(configuration);
  const log = (text: any) => {
    console.log(`[${new Date().toISOString()}] ${text.toString()}`);
  };
  const RETRYTIMES = 5; // retry the operation before giving up and throwing exception

  // onboarding the agent
  // Check in the local agent state storage if agent is onboarded.

if (!agent.IsOnBoarded()) {
    // wrapping the call in the retry function makes the agent a bit more resillient
    // if you don't want to retry the operations you can always just call await agent.OnBoard(); instead.
    await retry(RETRYTIMES, () => agent.OnBoard());
    log("Agent onboarded");
  }

  // you can use agent.Sdk().GetAssetManagementClient() to get the asset id and asset type from Insights Hub.
  const targetAssetId = "1234567....";
  const targetAssetType = `${agent.GetTenant()}.Engine`;

  // create data sourceconfiguration and mappings

  // this generates a data source configuration from an asset type
  const config = await agent.GenerateDataSourceConfiguration(targetAssetType);

  // create/overwrite the data source configuration
  await agent.PutDataSourceConfiguration(config);

  // create mappings for asset id
  const mappings = await agent.GenerateMappings(targetAssetId);
  // store mappings in InsightsHub
  await agent.PutDataMappings(mappings);

  // instead of creating the data source configuration and mappings separately
  // you can also just use the method below which takes care of everything
  // this is only used for 1:1 asset -> agent mappings
  // the method above can also map the data source configuration to multiple assets
  // just call GenerateMappings with different asset ids

  await agent.ConfigureAgentForAssetId(targetAssetId);

  // Check in the local agent state storage if agent has data source configuration.
  if (!agent.HasDataSourceConfiguration()) {
    await retry(RETRYTIMES, () => agent.GetDataSourceConfiguration());
    log("Configuration aquired");
  }

  for (let index = 0; index < 5; index++) {
    try {
      log(`Iteration : ${index}`);

      // if you have configred the data points in the Insights Hub UI you will have to use the long integer values instead of descriptive dataPointIds.

      const values: DataPointValue[] = [
        {
          dataPointId: "DP-Temperature",
          qualityCode: "0",
          value: (Math.sin(index) * (20 + (index % 2)) + 25).toString(),
        },
        {
          dataPointId: "DP-Pressure",
          qualityCode: "0",
          value: (Math.cos(index) * (20 + (index % 25)) + 25).toString(),
        },
        {
          dataPointId: "DP-Humidity",
          qualityCode: "0",
          value: ((index + 30) % 100).toString(),
        },
        {
          dataPointId: "DP-Acceleration",
          qualityCode: "0",
          value: (1000.0 + index).toString(),
        },
        {
          dataPointId: "DP-Frequency",
          qualityCode: "0",
          value: (60.0 + index * 0.1).toString(),
        },
        {
          dataPointId: "DP-Displacement",
          qualityCode: "0",
          value: (index % 10).toString(),
        },
        {
          dataPointId: "DP-Velocity",
          qualityCode: "0",
          value: (50.0 + index).toString(),
        },
      ];

      // same like above, you can also just call  await agent.PostData(values) if you don't want to retry the operation
      // this is how to send the data with specific timestamp
      // await agent.PostData(values, new Date(Date.now() - 86400 * 1000));

      await retry(RETRYTIMES, () => agent.PostData(values));
      log("Data posted");
      await sleep(1000);

      const event: MindSphereStandardEvent = {
        entityId: agent.ClientId(), // use assetid if you want to send event somewhere else :)
        sourceType: "Event",
        sourceId: "application",
        source: "Meowz",
        severity: 20, // 0-99 : 20:error, 30:warning, 40: information
        timestamp: new Date().toISOString(),
        description: "Test",
      };

      // send event with current timestamp; you can also just call agent.PostEvent(event) if you don't want to retry the operation
      await retry(RETRYTIMES, () => agent.PostEvent(event));
      log("event posted");
      await sleep(1000);

      // upload file
      // the upload-file can be a multipart operation and therefore can be configured to
      // retry the upload of the chunks instead the upload of the whole file.
      // if you don't specify the type , the mimetype is automatically determined by the library
      await agent.UploadFile(
        agent.ClientId(),
        "custom/mindsphere/path/package.json",
        "package.json",
        {
          retry: RETRYTIMES,
          description: "File uploaded with MindConnect-NodeJS Library",
          chunk: true, // the chunk parameter activates multipart upload
        }
      );

      log("file uploaded");
      await sleep(1000);

      const yesterday = new Date();
      yesterday.setDate(yesterday.getDate() - 1);
      const bulk: TimeStampedDataPoint[] = [
        {
          timestamp: yesterday.toISOString(),
          values: [
            { dataPointId: "DP-Temperature", qualityCode: "0", value: "10" },
            { dataPointId: "DP-Pressure", qualityCode: "0", value: "10" },
          ],
        },
        {
          timestamp: new Date().toISOString(),
          values: [
            { dataPointId: "DP-Temperature", qualityCode: "0", value: "10" },
            { dataPointId: "DP-Pressure", qualityCode: "0", value: "10" },
          ],
        },
      ];

      await retry(RETRYTIMES, () => agent.BulkPostData(bulk));
      log("bulk data uploaded");
      await sleep(1000);
    } catch (err) {
      // add proper error handling (e.g. store data somewhere, retry later etc. )
      console.error(err);
    }
  }
})();

Start the agent

npm start

This should produce the output like this:

> mc-agent-ts@1.0.0 start 
> tsc && node index.js

[2019-05-17T15:41:11.375Z] Iteration : 0
[2019-05-17T15:41:13.495Z] Agent onboarded
[2019-05-17T15:41:14.398Z] Configuration aquired
[2019-05-17T15:41:14.958Z] Data posted
[2019-05-17T15:41:16.409Z] event posted
[2019-05-17T15:41:18.285Z] bulk data uploaded
[2019-05-17T15:41:19.288Z] Iteration : 1
[2019-05-17T15:41:19.716Z] Data posted
[2019-05-17T15:41:21.325Z] event posted
[2019-05-17T15:41:23.445Z] bulk data uploaded
[2019-05-17T15:41:24.447Z] Iteration : 2
[2019-05-17T15:41:24.886Z] Data posted
[2019-05-17T15:41:26.289Z] event posted
[2019-05-17T15:41:30.744Z] bulk data uploaded