AttilaVarga
Tera Guru

AttilaVarga_0-1706525547877.png

 

In my previous article, I introduced the IT Operation Management product in an unusual way. I promised to also share the technical details of the solution.

 

Before we jump into the details, I would shortly summarise the topic of the previously mentioned article:

I have built a Lego vehicle, which can be controlled via Bluetooth (BLE-API), using Lego Boost MoveHub. Then I configured ServiceNow in order to control the vehicle, based on the capabilities of Discovery, Service Mapping and Event Management. If you haven't read this article yet, I highly recommend starting with that.

 

I am going to introduce the implementation steps, touching on the following topics:

 

  • Lego Vehicle control via BLE-API
  • RESTFul WebService implementation
  • Color sensor and SNMP trap
  • CMDB setup
  • Discovery configuration
  • Service Mapping configuration
  • Event Management configuration

 

Lego Boost MoveHub

 

The first milestone was to implement a solution, which can be used to control the Lego vehicle via Bluetooth (BLE - Bluetooth Low Energy). I used the Lego Boost MoveHub for this purpose.

Lego has released a documentation about its wireless BLE protocol. This is a massive documentation, so I finally decided to look for available implementations on the Internet. I found multiple ones, tested them and I selected a Javascript module, called node-poweredup. This one is quite well documented and can be used easily. It contains several types of useful API calls, which I decided to use in order to control the vehicle.

 

Bluetooth connection

 

The first challenge was to establish the BLE connection between my laptop and the MoveHub using a NodeJs application. There is a Javascript module, called bluetooth-hci-socket, which can be used for this purpose. Linux and MacOS operating systems can handle it well, but I have Windows on my laptop, so I had to do a small trick, changing the Bluetooth driver to a special one. There is a tool for this purpose, called Zadig.

 

AttilaVarga_0-1707140555089.png

 

There was another challenge, because my laptop is an older one, so the base source code of bluetooth-hci-socket did not contain the USB ID of my Bluetooth device. I had to add some enhancements to fix the issue. As you can see on the image above, the tool shows the USB ID, which I added to the original source code, into the following file: bluetooth-hci-socket/lib/usb.js

 

 

...
if (process.env.BLUETOOTH_HCI_SOCKET_USB_VID && process.env.BLUETOOTH_HCI_SOCKET_USB_PID) {
    var usbVid = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_VID);
    var usbPid = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_PID);

    debug('using USB VID = ' + usbVid + ', PID = ' + usbPid);

    if (process.env.BLUETOOTH_HCI_SOCKET_USB_BUS 
    && process.env.BLUETOOTH_HCI_SOCKET_USB_ADDRESS) {
      var usbBus = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_BUS);
      var usbAddress = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_ADDRESS);

      debug('using USB BUS = ' + usbBus + ', Address = ' + usbAddress);

      var usbDevices = usb.getDeviceList();

      for (var i = 0; i < usbDevices.length; i++) {
        var usbDeviceDesc = usbDevices[i].deviceDescriptor;

        if ((usbDeviceDesc.idVendor == usbVid) &&
            (usbDeviceDesc.idProduct == usbPid) &&
            (usbDevices[i].busNumber == usbBus) &&
            (usbDevices[i].deviceAddress == usbAddress)) {
          this._usbDevice = usbDevices[i];
        }
      }
    } else {
      this._usbDevice = usb.findByIds(usbVid, usbPid);
    }
} else {
    this._usbDevice = usb.findByIds(0x0a5c, 0x21e8) || 
usb.findByIds(0x19ff, 0x0239) || 
usb.findByIds(0x0a12, 0x0001) || 
usb.findByIds(0x0b05, 0x17cb) || 
usb.findByIds(0x8087, 0x07dc || 
/* MOD AV - custom BLE Driver */ usb.findByIds(0x8087, 0x0a2a));
}

if (!this._usbDevice) {
    throw new Error('No compatible USB Bluetooth 4.0 device found!');
}
...

 

 

The NodeJS application was able to identify my laptop's Bluetooth device after this modification, so I could execute the sample code of node-poweredup module to check how it works.

 

Lego wireless control via Bluetooth

 

Based on the example source code and the documentation, I could test all the commands, which I planned to use in order to control the vehicle:

  • Go Forward
  • Stop
  • Turn
  • Reading data from Color & Distance sensor

The following example shows the code of starting the vehicle and moving forward for a pre-defined time-frame.

 

 

async startMoving(activeTimeInSec, speed, waitResponse) {
    const activeTimeInMS = activeTimeInSec * 1000;
    this.motorA.setSpeed(speed, activeTimeInMS);
    if (waitResponse) {
        await this.motorB.setSpeed(speed, activeTimeInMS);
    }
    else {
        this.motorB.setSpeed(speed, activeTimeInMS);
    }
}

 

 

The MoveHub has two motors (motor A and B), which have to be controlled separately.

 

Implementing RESTFul Web Service

 

Once I could execute all planned commands, I had to implement a kind of remote controller. I used RESTFul Web service for this purpose. I created some HTTP endpoints in order to send commands to MoveHub from any type of web client.

For creating a RESTFul Web service, I used the express NodeJs web application framework. The following source code snippet is the HTTP endpoint, which can be used to start the vehicle moving forwards or backwards:

 

 

...
app = express();
...
this.app.get('/go/:time/:speed/:direction', async (req, res) => {
     this.legoApi.movingForward = req.params.direction == "forward";
     let speed: number = Number(req.params.speed);
     await this.legoApi.startMoving(req.params.time, req.params.direction == "forward" ? (speed) : (-1 * speed), false);
            res.setHeader('content-type', 'application/JSON');
            res.send({ result: "command was executed" });
        });

 

 

All the requests are similar to the example shown above. The implementation of the turning of the vehicle was somewhat difficult, because I had to calculate the turning angle based on the speed of the motor and the size of the "wheel". (In the case of a tracked vehicle one side goes forwards the other side goes backwards).

 

In addition to the control operations, I also created a special endpoint, which provides information about the connected device in JSON format:

 

 

{
    "uuid":"001653ad6b1f",
    "address":"00:16:53:ad:6b:1f",
    "localName":"LEGO Move Hub"
}

 

 

I will detail the importance of this HTTP endpoint in the Discovery chapter.

 

Color sensor and SNMP trap

 

Color sensor

 

Getting data from the Color sensor is a simple operation. Once the connection is established between MoveHub and the manager application and the sensor is activated, it starts sending information. This information is coming from the MoveHub as an asynchronous event, which the application has to subscribe to.

The code snippet below is an example to read the incoming information about sensed colors:

 

 

...
await hub.connect();
...
hub.on("color", (device, { color }) => {
  // Color processing
});

 

 

The color sensor sends a lot of data in a very short time, so I had to 'slow it down' a bit. I used a kind of queue-ing solution because of three reasons:

  • avoid sending the same information multiple times in a short duration
  • ensuring that data sending to ServiceNow will happen in the right sequence
  • ServiceNow is not able to react to a message fast, so I wanted to avoid incorrect data processing

At this point, I was able to read the colors from the sensor and process them. The next step was to create an SNMP trap and send it to ServiceNow.

 

SNMP trap

 

I used the net-snmp Javascript module for creating and sending SNMP trap to ServiceNow. As I wrote in the previous article I used the ENTITY-MIB because this is a known library. Sending an SNMP trap is quite easy, there are three pre-requirements:

  1. Need to establish a MID server
  2. Need to define an SNMP trap listener (It can be done easily, just need to follow the description on ServiceNow docs).

    AttilaVarga_0-1707144379800.png

     

  3. Need to send a well formatted message via UDP port

 

The code snippet below shows how I used net-snmp JS module to send SNMP trap to ServiceNow:

 

 

...
this.snmpSession = snmp.createSession(LISTENER_IP, "public", {
    port: 1162
});

let varbinds: any = [{
        oid: "1.3.6.1.2.1.47.1.1.1.1.7", // PhysicalName
        type: snmp.ObjectType.OctetString,
        value: vehicleAddress
    },
    {
        oid: "1.3.6.1.2.1.47.1.1.1.1.13", // PhysicalModelName
        type: snmp.ObjectType.OctetString,
        value: "LEGO Move Hub"
    },
    {
        oid: "1.3.6.1.2.1.47.1.1.1.1.2",
        type: snmp.ObjectType.OctetString,
        value: color
    },
    {
        oid: "1.3.6.1.2.1.47.1.1.1.1.2", // PhysicalDescription is used for threshold management
        type: snmp.ObjectType.OctetString,
        value: (color == "green" ? "300" : "100")
    },
    {
        oid: "1.3.6.1.2.1.47.1.1.1.1.5", // PhysicalClass
        type: snmp.ObjectType.Integer,
        value: 8
    },
    {
        oid: "1.3.6.1.2.1.47.1.1.1.1.8",
        type: snmp.ObjectType.OctetString,
        value: color == "red" ? "critical" : (color == "blue" ? "major" : "none")
    }
];

// version 2c should have been specified when creating the session
let oid: string = "1.3.6.1.2.1.47";
this.snmpSession.trap(oid, varbinds, function(error) {
    if (error)
        console.error(error);
});

 

 

Emergency stop logic

 

As the last topic of Lego MoveHub implementation part is the emergency stop. Once the color sensor receives the color red, the the application calls a function which stops the vehicle. During the different use-case testing I recognised, that ServiceNow needs some time to process messages coming from the MoveHub. To make the demonstration more attractive, I added a delay of a few seconds between the detection of the red signal and the application sending the stop command to the MoveHub.

 

Configuration steps on ServiceNow side

 

CMDB setup

 

The Lego MoveHub and the RESTFul Web service are ready to be used and need to be stored in CMDB in order for Event management to be able to control them. I defined two additional CI classes in ServiceNow:

 

  • LEGO MoveHUB ➡️ This is a physical Hardware, inherited from Configuration Item (cmdb_ci)
  • Lego Vehicle Manager ➡️ This is a Software, inherited from Application (cmdb_ci_appl)

I used CMDB CI Class Manager for creating the tables, because it provides one layout for managing and organising Configuration Items and the related data rules. Furthermore, it provides an easy-to-understand layout for the quick management of CMDB. I used this tool for defining the tables, columns, identification rules and the CI class icons. I wanted to add my icons to the CI classes, so I followed a description which is available on the Community. The result can be seen on the image below: 

 

AttilaVarga_1-1707145866462.png

 

 

Discovery configuration

 

The CMDB enhancement is ready, the next step is to fill the tables with data. I used Process classification based on a horizontal pattern probe in order to discover the Web Service and the MoveHub.

First I had to create the filter condition to find the NodeJS process on the host, which makes the Web Service available.

 

AttilaVarga_0-1707147532280.png

 

 

Then, I created a new Horizontal Discovery pattern and related it to the Process Classification record.

 

AttilaVarga_1-1707147588632.png

 

The pattern has to contain at least one element in the Identification Section. This element defines the steps which are executed during the process.

 

AttilaVarga_2-1707147671106.png

 

I defined five steps for gathering all the necessary information from the Web Service, MoveHub and storing them in CMDB.

 

AttilaVarga_3-1707147814050.png

 

1. Step: This simply checks if the process is a NodeJs one. Otherwise, the operation is terminated.

 

AttilaVarga_4-1707147867043.png

 

2. Step: This step executes an HTTP GET request for collecting the connected Lego MoveHub details. Here I would refer back to the chapter about Web Service, where I wrote, that I implemented an end-point to get information from the MoveHub in order to be able identify it.

 

AttilaVarga_9-1707149196825.png

 

 

3. Step, 4. Step: The next two steps are about storing the gathered data into the corresponding tables in CMDB:

 

AttilaVarga_5-1707148192907.png

 

AttilaVarga_7-1707148751676.png

 

 

5. Step: The last step is responsible for creating the relationship between Vehicle Manager and MoveHub.

 

AttilaVarga_8-1707148763652.png

 

Once I was done, I tested all the steps using the debug capability of Pattern designer. Finally I saved and published the pattern. Afterwards I executed a quick discovery process. The result can be seen on the image below:

 

AttilaVarga_0-1707645329524.png

 

The discovery process is done the next phase is the Service Mapping.

 

Service Mapping configuration

 

If you read my previous article, you remember that I decided to use the Tag-based Service Mapping. I spent a lot of time figuring out the best solution for creating the Service Map. The goal was to create a CI structure, which accurately represents reality. This is the configuration I came up with.

 

Configuration steps

 

As its name suggests, this mapping type is based on CI related Tag(s), so as a first step I had to define a CI Tag category and CI Tag key element. This key will be related to all CIs and used for building the service.

 

AttilaVarga_1-1707154404281.png

 

The next step was creating a new Tag-based service family record to define how to correlate the selected tag values to each other and create a Service Map.

 

AttilaVarga_2-1707154452127.png

 

The relationship between the Lego Vehicle Manager and the Lego MoveHub had to be defined in order for the corresponding relationship to be created by the system on the Service Map. I created a CI Relationship Type Rule definition, which I added to a Traversal Rule:
 

AttilaVarga_3-1707154592060.png

 

AttilaVarga_4-1707154614262.png

 

I didn't want to add the Tag manually to the CIs, so I created a Pattern Post script which does this operation during the Discovery process.

 

AttilaVarga_4-1707205459389.png

 

Let me give a short explanation to the script above. The logic is simple. The payload.items variable is an array, which contains data from all discovered CIs. The script iterates through these CI elements and if necessary creates a new Tag.

I executed the discovery again and the new Tag records were created and related to the corresponding CIs.

 

AttilaVarga_5-1707205764017.png

 

I opened again the Tag-based service family record and I clicked Manually update candidates and then, View service candidates UI actions.

A modal window appeared where I could select the corresponding service candidate and clicked the Map selected button. The result of these steps was that the new Application Service was generated in the system and related to the Mapped Services section of the Tag-based service family record.

 

AttilaVarga_0-1707205042070.png

 

I clicked the View map link and checked the generated Service Map. It looked like how I expected it to. The service is related directly to the Remote Manager, which is running on a computer and manages the Lego MoveHub.

 

AttilaVarga_1-1707205103292.png

 

The service configuration is done and ready to be managed by the Event Management.

 

Event Management configuration

 

So we have a Lego vehicle, which can be controlled via a Web Service. The RESTFul API is hosted by a NodeJS Express Web application Framework. The vehicle remote management software is able to get and process information from the color sensor and send SNMP traps to ServiceNow via the configured SNMP listener. Furthermore the CMDB configuration is also done and the Service Map is ready to be used.

The OOTB behaviour of SNMP listener is the following:

When a trap is sent to ServiceNow, an Event is created into the em_event table. This is the first point where we have to decide that the Event is a valid one or it can be correlated.

Event rules can be used for making decisions about incoming events. I created a new one with the following settings:

  • a filter definition so that the rule is evaluated only in my specific case
  • a field transformation definition to use and store the corresponding data from the event
  • threshold for correlating noises
  • a data binding in order for ServiceNow to be able to identify the correct CI

 

AttilaVarga_3-1707206879771.png

 

 

AttilaVarga_6-1707207049165.png

 

 

AttilaVarga_7-1707207085205.png

 

 

AttilaVarga_8-1707207119787.png

 

 

If the conditions match, the system generates an Alert. I created two Alert Management rules, one for the Critical, and another one for the Major alert handling.

 

Critical alert handler

 

This alert handler is executed when the Alert's Severity is Critical. I added some additional filter conditions, which can be seen on the image below:

 

AttilaVarga_3-1707212391329.png

 

If the conditions match, three different actions can be used:

  • Executing one or multiple Remediation Subflows
  • Executing one or multiple Remediation Workflows (This action is marked as a deprecated action by ServiceNow, the recommendation is using Subflows instead of this.)
  • Launching a web application

 

In this use-case I used an OOTB available Subflow for creating an ITSM Incident.

 

AttilaVarga_2-1707212379844.png

 

Major alert handling

 

This alert handler is executed when the Alert's Severity is Major. It is very similar to the previous one.

 

AttilaVarga_4-1707212467428.png

 

In this case I used a custom Subflow, which controls the vehicle and finally closes the Alert.

 

AttilaVarga_5-1707212519627.png

 

Custom remediation flow

 

The purpose of the custom remediation flow is to stop the vehicle and turn it back, afterwards close the Alert. I created some Flow actions, which contain a REST step in order to send commands to the Lego vehicle via Lego Remote Manager RESTFul API. I used these actions in the Subflow definition. As a final step, I added the Close Alert Subflow (which is an OOTB one) to the process definition.

 

AttilaVarga_6-1707212972887.png

 

ServiceNow gives an easy way to call REST APIs from Flow Designer, it is called REST step. This action is not available if one of the IntegrationHub plugins is not installed. The configuration, which I used, can be seen on the following image.

 

AttilaVarga_7-1707213246162.png

 

In order to see real time information on the Service Map, I clicked the Monitor Service button. After this step I could follow the events on the Map in real time, which I demonstrated in the videos in the previous article.

 

AttilaVarga_2-1707205154510.png

 

 

AttilaVarga_0-1707206553256.png

 

 

Final thoughts

 

This was a great opportunity to try a lot of capabilities of ServiceNow, test them, and introduce the IT Operation Management core features in a unique way. There were several challenges during the implementation. One time I accidentally upgraded the firmware of MoveHub, which caused a lot of headache for me 🙂.

 

The question may arise, was the time invested worth it? Well, if these two articles give motivation to people to try something new, or to help them understand how ITOM works, I would say yes, it was worth it.

 

If you have comments or suggested improvements on this topic, please feel free to share them with the community.

 

I know this was a quite long article, thank you for reading, I hope you enjoyed it 🙂.

Comments
Jodi Hartman1
Tera Expert

Wow!  Thank you for writing such a detailed article and sharing with the community!  Great work!  

Aneesh-D
Tera Guru
Tera Guru

Thank you for sharing the details. This was much awaited one after your initial one!!

Version history
Last update:
‎02-12-2024 08:03 AM
Updated by:
Contributors